Example #1
0
/* ARGSUSED */
int
sys_setreuid(struct proc *p, void *v, register_t *retval)
{
	struct sys_setreuid_args /* {
		syscallarg(uid_t) ruid;
		syscallarg(uid_t) euid;
	} */ *uap = v;
	struct pcred *pc = p->p_cred;
	struct sys_setresuid_args sresuidargs;
	uid_t ruid, euid;

	ruid = SCARG(&sresuidargs, ruid) = SCARG(uap, ruid);
	euid = SCARG(&sresuidargs, euid) = SCARG(uap, euid);

	/*
	 * The saved uid presents a bit of a dilemma, as it did not
	 * exist when setreuid(2) was conceived.  We only set the saved
	 * uid when the real uid is specified and either its value would
	 * change, or where the saved and effective uids are different.
	 */
	if (ruid != (uid_t)-1 && (ruid != pc->p_ruid ||
	    pc->p_svuid != (euid != (uid_t)-1 ? euid : pc->pc_ucred->cr_uid)))
		SCARG(&sresuidargs, suid) = ruid;
	else
		SCARG(&sresuidargs, suid) = (uid_t)-1;

	return (sys_setresuid(p, &sresuidargs, retval));
}
Example #2
0
File: uid16.c Project: 274914765/C
asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
{
    long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid),
                 low2highuid(suid));
    /* avoid REGPARM breakage on x86: */
    asmlinkage_protect(3, ret, ruid, euid, suid);
    return ret;
}
Example #3
0
SYSCALL_DEFINE3(setresuid16, old_uid_t, ruid, old_uid_t, euid, old_uid_t, suid)
{
	long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid),
				 low2highuid(suid));
	/* avoid REGPARM breakage on x86: */
	asmlinkage_protect(3, ret, ruid, euid, suid);
	return ret;
}
Example #4
0
asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
{
	return sys_setresuid(low2highuid(ruid), low2highuid(euid),
		low2highuid(suid));
}
Example #5
0
asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
{
	return sys_setresuid(low2highuid(ruid), low2highuid(euid),
		low2highuid(suid));
}
Example #6
0
int ckpt_restore_cred(ckpt_desc_t desc)
{
    int ret = 0;
    ckpt_cred_t cred;
    gid_t *groups = NULL;
    const struct cred *curr_cred = current->cred;

    log_restore_cred("restoring cred ...");
    if (ckpt_read(desc, &cred, sizeof(ckpt_cred_t)) != sizeof(ckpt_cred_t)) {
        log_err("failed to get cred");
        return -EIO;
    }

    if (cred.ngroups > NGROUPS_MAX) {
        log_err("ngroups (%d) > NGROUPS_MAX", cred.ngroups);
        return -EINVAL;
    }

    if (cred.ngroups > 0) {
        int i;
        size_t size = cred.ngroups * sizeof(gid_t);
        struct group_info *gi = curr_cred->group_info;

        groups = vmalloc(size);
        if (!groups) {
            log_err("no memory");
            return -ENOMEM;
        }

        if (ckpt_read(desc, groups, size) != size) {
            log_err("failed to get groups");
            ret = -EIO;
            goto out;
        }

        for (i = 0; i < cred.ngroups; i++) {
            if (!groups_search(gi, groups[i])) {
                mm_segment_t fs = get_fs();
                set_fs(KERNEL_DS);
                ret = sys_setgroups(cred.ngroups, groups);
                set_fs(fs);
                if (ret < 0) {
                    log_err("failed to set groups");
                    goto out;
                }
                break;
            }
        }
    }

    current->gpid = cred.gpid;
    ret = sys_setresgid(cred.gid, cred.egid, cred.sgid);
    if (ret < 0) {
        log_err("failed to restore gid");
        goto out;
    }

    ret = sys_setresuid(cred.uid, cred.euid, cred.suid);
    if (ret < 0) {
        log_err("failed to restore uid");
        goto out;
    }

    if ((curr_cred->euid == curr_cred->uid) && (curr_cred->egid == curr_cred->gid))
        set_dumpable(current->mm, 1);
    else
        set_dumpable(current->mm, *compat_suid_dumpable);
    log_restore_pos(desc);
out:
    if (groups)
        vfree(groups);
    return ret;
}
Example #7
0
int cr_load_creds(cr_rstrt_proc_req_t *proc_req)
{
    cr_errbuf_t *eb = proc_req->req->errbuf;
    struct cr_context_creds cf_creds;
    int retval;
    gid_t *groups = NULL;

    CR_KTRACE_HIGH_LVL("%d: Restoring credentials", current->pid);

    retval = cr_kread(eb, proc_req->file, &cf_creds, sizeof(cf_creds));
    if (retval < sizeof(cf_creds)) {
	CR_ERR_PROC_REQ(proc_req, "credentials: read returned %d", retval);
        goto out;
    }
     
    if (cf_creds.ngroups > CR_NGROUPS_MAX) {
	CR_ERR_PROC_REQ(proc_req, "Invalid supplemental group count (%d)", (int)cf_creds.ngroups);
	retval = -EINVAL;
	goto out;
    } else if (cf_creds.ngroups) {
	size_t sizeof_groups = cf_creds.ngroups*sizeof(gid_t);
	groups = vmalloc(sizeof_groups);
	retval = -ENOMEM;
	if (groups == NULL) {
	    goto out;
	}

	retval = cr_kread(eb, proc_req->file, groups, sizeof_groups);
	if (retval < sizeof_groups) {
	    CR_ERR_PROC_REQ(proc_req, "groups: read returned %d", retval);
            goto out_vfree;
        }
    }

#if CR_RESTORE_IDS
    if (cf_creds.ngroups) {
      #if CR_HAVE_GROUP_INFO || defined(CR_KCODE_groups_search) || !defined(CR_KCODE_supplemental_group_member)
	cr_group_info_t gi = cr_current_groups();
      #endif
	int i;
	/* Search for any required "expansion" of the group set */
	for (i = 0; i < cf_creds.ngroups; ++i) {
	    gid_t g = groups[i];
	    int gid_ok = 0; /* Assume no match for this gid */

    #if defined(CR_KCODE_groups_search)
	    gid_ok = groups_search((struct group_info *)gi, g); // search is const, but not declared as such
    #elif defined(CR_KCODE_supplemental_group_member)
	    gid_ok = supplemental_group_member(g);
    #else
	    /* Just in case groups_search() or supplemental_group_member()
	     * is not found (each was static in some kernels) */
	    int j;
	    for (j = 0; j < gi->ngroups; ++j) {
                if (g == CR_GROUP_AT(gi, j)) {
		    gid_ok = 1; /* OK, g is in the existing set */
		    break;
		}
	    }
    #endif

	    if (!gid_ok) {
	        /* If we reach here then we've seen a supplemental group in the
	         * saved context, which is not present in the current list.
		 * The set_groups() call checks permissions for us.  If we fail,
		 * then we must not have enough credentials.
		 */
		mm_segment_t oldfs = get_fs();
		set_fs(KERNEL_DS);
		retval = sys_setgroups(cf_creds.ngroups, groups);
		set_fs(oldfs);
		if (retval < 0) {
		    CR_ERR_PROC_REQ(proc_req, "Failed to restore supplemental group(s).");
		    goto out_vfree;
		}
		CR_KTRACE_LOW_LVL("Restored %d supplemental group(s)", cf_creds.ngroups);
		break; /* no need to continue the i loop */
	    }
	}
  #if CR_HAVE_GROUP_INFO
	(void)cr_insert_object(proc_req->req->map, (void *)cf_creds.group_info, (void *)gi, GFP_KERNEL);
  #endif
    }
  #if CR_HAVE_GROUP_INFO
    else {
	// NOTE: requires restore order match save order
	struct group_info *found_group_info = NULL;

	if (!cr_find_object(proc_req->req->map, (void *)cf_creds.group_info, (void **)&found_group_info)) {
	   // Nothing to do
	} else if (found_group_info != cr_current_groups()) {
	    // validation and sort were done previously, but are not worth avoiding
	    set_current_groups(found_group_info);
	    CR_KTRACE_LOW_LVL("Reuse cached group_info %p", found_group_info);
	} else {
	    CR_KTRACE_LOW_LVL("Cached group_info == current");
	}
    }
  #endif

    {
	cr_cred_t my_cred = cr_current_cred();

	/* The set_setresgid() call checks permissions for us, always OK if no change . */
	retval = sys_setresgid(cf_creds.gid, cf_creds.egid, cf_creds.sgid);
	if (retval < 0) {
	    CR_ERR_PROC_REQ(proc_req, "Failed to restore real/effective/saved gids.");
	    goto out_vfree;
	}
	CR_KTRACE_LOW_LVL("Restored gids");

	/* The set_setresuid() call checks permissions for us, always OK if no change . */
	retval = sys_setresuid(cf_creds.uid, cf_creds.euid, cf_creds.suid);
	if (retval < 0) {
	    CR_ERR_PROC_REQ(proc_req, "Failed to restore real/effective/saved uids.");
	    goto out_vfree;
	}
	CR_KTRACE_LOW_LVL("Restored uids");

        /* 
	 * sys_setresuid sets current->mm->dumpable to suid_dumpable if the
	 * call was successful.  This can have some weird side-effects on
	 * restarted jobs, like /proc/self/fd will not be accessable.  
         *
	 * We should probably save this flag and restore it if we ever
	 * support real setuid checkpoints from the user, but for now we'll
	 * just set the flag to 1 if the user had permission to restore their
	 * credentials in the first place.  This should mimic the behavior
         * of exec.
         *
         * Set the dumpable flag for the process, taken from 2.6.22 fs/exec.c
         */
        if (my_cred->euid == my_cred->uid && my_cred->egid == my_cred->gid) {
            cr_set_dumpable(current->mm, 1);
        } else {
            cr_set_dumpable(current->mm, cr_suid_dumpable);
        }
    }
#endif	 /* CR_RESTORE_IDS */

out_vfree:
    vfree(groups);

out:
    return retval;
}
Example #8
0
static int restore_creds(CredsEntry *ce)
{
	int b, i, ret;
	struct cap_header hdr;
	struct cap_data data[_LINUX_CAPABILITY_U32S_3];

	/*
	 * We're still root here and thus can do it without failures.
	 */

	/*
	 * First -- set the SECURE_NO_SETUID_FIXUP bit not to
	 * lose caps bits when changing xids.
	 */

	ret = sys_prctl(PR_SET_SECUREBITS, 1 << SECURE_NO_SETUID_FIXUP, 0, 0, 0);
	if (ret) {
		pr_err("Unable to set SECURE_NO_SETUID_FIXUP: %d\n", ret);
		return -1;
	}

	/*
	 * Second -- restore xids. Since we still have the CAP_SETUID
	 * capability nothing should fail. But call the setfsXid last
	 * to override the setresXid settings.
	 */

	ret = sys_setresuid(ce->uid, ce->euid, ce->suid);
	if (ret) {
		pr_err("Unable to set real, effective and saved user ID: %d\n", ret);
		return -1;
	}

	sys_setfsuid(ce->fsuid);
	if (sys_setfsuid(-1) != ce->fsuid) {
		pr_err("Unable to set fsuid\n");
		return -1;
	}

	ret = sys_setresgid(ce->gid, ce->egid, ce->sgid);
	if (ret) {
		pr_err("Unable to set real, effective and saved group ID: %d\n", ret);
		return -1;
	}

	sys_setfsgid(ce->fsgid);
	if (sys_setfsgid(-1) != ce->fsgid) {
		pr_err("Unable to set fsgid\n");
		return -1;
	}

	/*
	 * Third -- restore securebits. We don't need them in any
	 * special state any longer.
	 */

	ret = sys_prctl(PR_SET_SECUREBITS, ce->secbits, 0, 0, 0);
	if (ret) {
		pr_err("Unable to set PR_SET_SECUREBITS: %d\n", ret);
		return -1;
	}

	/*
	 * Fourth -- trim bset. This can only be done while
	 * having the CAP_SETPCAP capablity.
	 */

	for (b = 0; b < CR_CAP_SIZE; b++) {
		for (i = 0; i < 32; i++) {
			if (b * 32 + i > cap_last_cap)
				break;
			if (ce->cap_bnd[b] & (1 << i))
				/* already set */
				continue;
			ret = sys_prctl(PR_CAPBSET_DROP, i + b * 32, 0, 0, 0);
			if (ret) {
				pr_err("Unable to drop capability %d: %d\n",
								i + b * 32, ret);
				return -1;
			}
		}
	}

	/*
	 * Fifth -- restore caps. Nothing but cap bits are changed
	 * at this stage, so just do it.
	 */

	hdr.version = _LINUX_CAPABILITY_VERSION_3;
	hdr.pid = 0;

	BUILD_BUG_ON(_LINUX_CAPABILITY_U32S_3 != CR_CAP_SIZE);

	for (i = 0; i < CR_CAP_SIZE; i++) {
		data[i].eff = ce->cap_eff[i];
		data[i].prm = ce->cap_prm[i];
		data[i].inh = ce->cap_inh[i];
	}

	ret = sys_capset(&hdr, data);
	if (ret) {
		pr_err("Unable to restore capabilities: %d\n", ret);
		return -1;
	}

	return 0;
}