Example #1
0
File: uid16.c Project: 274914765/C
asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist)
{
    struct group_info *group_info;
    int retval;

    if (!capable(CAP_SETGID))
        return -EPERM;
    if ((unsigned)gidsetsize > NGROUPS_MAX)
        return -EINVAL;

    group_info = groups_alloc(gidsetsize);
    if (!group_info)
        return -ENOMEM;
    retval = groups16_from_user(group_info, grouplist);
    if (retval) {
        put_group_info(group_info);
        return retval;
    }

    retval = set_current_groups(group_info);
    put_group_info(group_info);

    return retval;
}
Example #2
0
SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
{
	struct group_info *group_info;
	int retval;

	if (!nsown_capable(CAP_SETGID))
		return -EPERM;
	if ((unsigned)gidsetsize > NGROUPS_MAX)
		return -EINVAL;

	group_info = groups_alloc(gidsetsize);
	if (!group_info)
		return -ENOMEM;
	retval = groups16_from_user(group_info, grouplist);
	if (retval) {
		put_group_info(group_info);
		return retval;
	}

	retval = set_current_groups(group_info);
	put_group_info(group_info);

	return retval;
}
Example #3
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 #4
-1
int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
{
	struct svc_cred	cred = rqstp->rq_cred;
	int i;
	int flags = nfsexp_flags(rqstp, exp);
	int ret;

	if (flags & NFSEXP_ALLSQUASH) {
		cred.cr_uid = exp->ex_anon_uid;
		cred.cr_gid = exp->ex_anon_gid;
		cred.cr_group_info = groups_alloc(0);
	} else if (flags & NFSEXP_ROOTSQUASH) {
		struct group_info *gi;
		if (!cred.cr_uid)
			cred.cr_uid = exp->ex_anon_uid;
		if (!cred.cr_gid)
			cred.cr_gid = exp->ex_anon_gid;
		gi = groups_alloc(cred.cr_group_info->ngroups);
		if (gi)
			for (i = 0; i < cred.cr_group_info->ngroups; i++) {
				if (!GROUP_AT(cred.cr_group_info, i))
					GROUP_AT(gi, i) = exp->ex_anon_gid;
				else
					GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
			}
		cred.cr_group_info = gi;
	} else
		get_group_info(cred.cr_group_info);

	if (cred.cr_uid != (uid_t) -1)
		current->fsuid = cred.cr_uid;
	else
		current->fsuid = exp->ex_anon_uid;
	if (cred.cr_gid != (gid_t) -1)
		current->fsgid = cred.cr_gid;
	else
		current->fsgid = exp->ex_anon_gid;

	if (!cred.cr_group_info)
		return -ENOMEM;
	ret = set_current_groups(cred.cr_group_info);
	put_group_info(cred.cr_group_info);
	if ((cred.cr_uid)) {
		current->cap_effective =
			cap_drop_nfsd_set(current->cap_effective);
	} else {
		current->cap_effective =
			cap_raise_nfsd_set(current->cap_effective,
					   current->cap_permitted);
	}
	return ret;
}