Christian Brauner (Amutable)exec_state: relocate dumpable information6b1c66c5 months agoHistory
3074 lines · 72.8 KB · C
RawDownload
	else		goto error; 	retval = security_task_fix_setgid(new, old, LSM_SETID_ID);	if (retval < 0)		goto error; 	return commit_creds(new); error:	abort_creds(new);	return retval;} SYSCALL_DEFINE1(setgid, gid_t, gid){	return __sys_setgid(gid);} /* * change the user struct in a credentials set to match the new UID */static int set_user(struct cred *new){	struct user_struct *new_user; 	new_user = alloc_uid(new->uid);	if (!new_user)		return -EAGAIN; 	free_uid(new->user);	new->user = new_user;	return 0;} static void flag_nproc_exceeded(struct cred *new){	if (new->ucounts == current_ucounts())		return; 	/*	 * We don't fail in case of NPROC limit excess here because too many	 * poorly written programs don't check set*uid() return code, assuming	 * it never fails if called by root.  We may still enforce NPROC limit	 * for programs doing set*uid()+execve() by harmlessly deferring the	 * failure to the execve() stage.	 */	if (is_rlimit_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&			new->user != INIT_USER)		current->flags |= PF_NPROC_EXCEEDED;	else		current->flags &= ~PF_NPROC_EXCEEDED;} /* * Unprivileged users may change the real uid to the effective uid * or vice versa.  (BSD-style) * * If you set the real uid at all, or set the effective uid to a value not * equal to the real uid, then the saved uid is set to the new effective uid. * * This makes it possible for a setuid program to completely drop its * privileges, which is often a useful assertion to make when you are doing * a security audit over a program. * * The general idea is that a program which uses just setreuid() will be * 100% compatible with BSD.  A program which uses just setuid() will be * 100% compatible with POSIX with saved IDs. */long __sys_setreuid(uid_t ruid, uid_t euid){	struct user_namespace *ns = current_user_ns();	const struct cred *old;	struct cred *new;	int retval;	kuid_t kruid, keuid; 	kruid = make_kuid(ns, ruid);	keuid = make_kuid(ns, euid); 	if ((ruid != (uid_t) -1) && !uid_valid(kruid))		return -EINVAL;	if ((euid != (uid_t) -1) && !uid_valid(keuid))		return -EINVAL; 	new = prepare_creds();	if (!new)		return -ENOMEM;	old = current_cred(); 	retval = -EPERM;	if (ruid != (uid_t) -1) {		new->uid = kruid;		if (!uid_eq(old->uid, kruid) &&		    !uid_eq(old->euid, kruid) &&		    !ns_capable_setid(old->user_ns, CAP_SETUID))			goto error;	} 	if (euid != (uid_t) -1) {		new->euid = keuid;		if (!uid_eq(old->uid, keuid) &&		    !uid_eq(old->euid, keuid) &&		    !uid_eq(old->suid, keuid) &&		    !ns_capable_setid(old->user_ns, CAP_SETUID))			goto error;	} 	if (!uid_eq(new->uid, old->uid)) {		retval = set_user(new);		if (retval < 0)			goto error;	}	if (ruid != (uid_t) -1 ||	    (euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))		new->suid = new->euid;	new->fsuid = new->euid; 	retval = security_task_fix_setuid(new, old, LSM_SETID_RE);	if (retval < 0)		goto error; 	retval = set_cred_ucounts(new);	if (retval < 0)		goto error; 	flag_nproc_exceeded(new);	return commit_creds(new); error:	abort_creds(new);	return retval;} SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid){	return __sys_setreuid(ruid, euid);} /* * setuid() is implemented like SysV with SAVED_IDS * * Note that SAVED_ID's is deficient in that a setuid root program * like sendmail, for example, cannot set its uid to be a normal * user and then switch back, because if you're root, setuid() sets * the saved uid too.  If you don't like this, blame the bright people * in the POSIX committee and/or USG.  Note that the BSD-style setreuid() * will allow a root program to temporarily drop privileges and be able to * regain them by swapping the real and effective uid. */long __sys_setuid(uid_t uid){	struct user_namespace *ns = current_user_ns();	const struct cred *old;	struct cred *new;	int retval;	kuid_t kuid; 	kuid = make_kuid(ns, uid);	if (!uid_valid(kuid))		return -EINVAL; 	new = prepare_creds();	if (!new)		return -ENOMEM;	old = current_cred(); 	retval = -EPERM;	if (ns_capable_setid(old->user_ns, CAP_SETUID)) {		new->suid = new->uid = kuid;		if (!uid_eq(kuid, old->uid)) {			retval = set_user(new);			if (retval < 0)				goto error;		}	} else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) {		goto error;	} 	new->fsuid = new->euid = kuid; 	retval = security_task_fix_setuid(new, old, LSM_SETID_ID);	if (retval < 0)		goto error; 	retval = set_cred_ucounts(new);	if (retval < 0)		goto error; 	flag_nproc_exceeded(new);	return commit_creds(new); error:	abort_creds(new);	return retval;} SYSCALL_DEFINE1(setuid, uid_t, uid){	return __sys_setuid(uid);}  /* * This function implements a generic ability to update ruid, euid, * and suid.  This allows you to implement the 4.4 compatible seteuid(). */long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid){	struct user_namespace *ns = current_user_ns();	const struct cred *old;	struct cred *new;	int retval;	kuid_t kruid, keuid, ksuid;	bool ruid_new, euid_new, suid_new; 	kruid = make_kuid(ns, ruid);	keuid = make_kuid(ns, euid);	ksuid = make_kuid(ns, suid); 	if ((ruid != (uid_t) -1) && !uid_valid(kruid))		return -EINVAL; 	if ((euid != (uid_t) -1) && !uid_valid(keuid))		return -EINVAL; 	if ((suid != (uid_t) -1) && !uid_valid(ksuid))		return -EINVAL; 	old = current_cred(); 	/* check for no-op */	if ((ruid == (uid_t) -1 || uid_eq(kruid, old->uid)) &&	    (euid == (uid_t) -1 || (uid_eq(keuid, old->euid) &&				    uid_eq(keuid, old->fsuid))) &&	    (suid == (uid_t) -1 || uid_eq(ksuid, old->suid)))		return 0; 	ruid_new = ruid != (uid_t) -1        && !uid_eq(kruid, old->uid) &&		   !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid);	euid_new = euid != (uid_t) -1        && !uid_eq(keuid, old->uid) &&		   !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid);	suid_new = suid != (uid_t) -1        && !uid_eq(ksuid, old->uid) &&		   !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid);	if ((ruid_new || euid_new || suid_new) &&	    !ns_capable_setid(old->user_ns, CAP_SETUID))		return -EPERM; 	new = prepare_creds();	if (!new)		return -ENOMEM; 	if (ruid != (uid_t) -1) {		new->uid = kruid;		if (!uid_eq(kruid, old->uid)) {			retval = set_user(new);			if (retval < 0)				goto error;		}	}	if (euid != (uid_t) -1)		new->euid = keuid;	if (suid != (uid_t) -1)		new->suid = ksuid;	new->fsuid = new->euid; 	retval = security_task_fix_setuid(new, old, LSM_SETID_RES);	if (retval < 0)		goto error; 	retval = set_cred_ucounts(new);	if (retval < 0)		goto error; 	flag_nproc_exceeded(new);	return commit_creds(new); error:	abort_creds(new);	return retval;} SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid){	return __sys_setresuid(ruid, euid, suid);} SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp){	const struct cred *cred = current_cred();	int retval;	uid_t ruid, euid, suid; 	ruid = from_kuid_munged(cred->user_ns, cred->uid);	euid = from_kuid_munged(cred->user_ns, cred->euid);	suid = from_kuid_munged(cred->user_ns, cred->suid); 	retval = put_user(ruid, ruidp);	if (!retval) {		retval = put_user(euid, euidp);		if (!retval)			return put_user(suid, suidp);	}	return retval;} /* * Same as above, but for rgid, egid, sgid. */long __sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid){	struct user_namespace *ns = current_user_ns();	const struct cred *old;	struct cred *new;	int retval;	kgid_t krgid, kegid, ksgid;	bool rgid_new, egid_new, sgid_new; 	krgid = make_kgid(ns, rgid);	kegid = make_kgid(ns, egid);	ksgid = make_kgid(ns, sgid); 	if ((rgid != (gid_t) -1) && !gid_valid(krgid))		return -EINVAL;	if ((egid != (gid_t) -1) && !gid_valid(kegid))		return -EINVAL;	if ((sgid != (gid_t) -1) && !gid_valid(ksgid))		return -EINVAL; 	old = current_cred(); 	/* check for no-op */	if ((rgid == (gid_t) -1 || gid_eq(krgid, old->gid)) &&	    (egid == (gid_t) -1 || (gid_eq(kegid, old->egid) &&				    gid_eq(kegid, old->fsgid))) &&	    (sgid == (gid_t) -1 || gid_eq(ksgid, old->sgid)))		return 0; 	rgid_new = rgid != (gid_t) -1        && !gid_eq(krgid, old->gid) &&		   !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid);	egid_new = egid != (gid_t) -1        && !gid_eq(kegid, old->gid) &&		   !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid);	sgid_new = sgid != (gid_t) -1        && !gid_eq(ksgid, old->gid) &&		   !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid);	if ((rgid_new || egid_new || sgid_new) &&	    !ns_capable_setid(old->user_ns, CAP_SETGID))		return -EPERM; 	new = prepare_creds();	if (!new)		return -ENOMEM; 	if (rgid != (gid_t) -1)		new->gid = krgid;	if (egid != (gid_t) -1)		new->egid = kegid;	if (sgid != (gid_t) -1)		new->sgid = ksgid;	new->fsgid = new->egid; 	retval = security_task_fix_setgid(new, old, LSM_SETID_RES);	if (retval < 0)		goto error; 	return commit_creds(new); error:	abort_creds(new);	return retval;} SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid){	return __sys_setresgid(rgid, egid, sgid);} SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp){	const struct cred *cred = current_cred();	int retval;	gid_t rgid, egid, sgid; 	rgid = from_kgid_munged(cred->user_ns, cred->gid);	egid = from_kgid_munged(cred->user_ns, cred->egid);	sgid = from_kgid_munged(cred->user_ns, cred->sgid); 	retval = put_user(rgid, rgidp);	if (!retval) {		retval = put_user(egid, egidp);		if (!retval)			retval = put_user(sgid, sgidp);	} 	return retval;}  /* * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This * is used for "access()" and for the NFS daemon (letting nfsd stay at * whatever uid it wants to). It normally shadows "euid", except when * explicitly set by setfsuid() or for access.. */long __sys_setfsuid(uid_t uid){	const struct cred *old;	struct cred *new;	uid_t old_fsuid;	kuid_t kuid; 	old = current_cred();	old_fsuid = from_kuid_munged(old->user_ns, old->fsuid); 	kuid = make_kuid(old->user_ns, uid);	if (!uid_valid(kuid))		return old_fsuid; 	new = prepare_creds();	if (!new)		return old_fsuid; 	if (uid_eq(kuid, old->uid)  || uid_eq(kuid, old->euid)  ||	    uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||	    ns_capable_setid(old->user_ns, CAP_SETUID)) {		if (!uid_eq(kuid, old->fsuid)) {			new->fsuid = kuid;			if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)				goto change_okay;		}	} 	abort_creds(new);	return old_fsuid; change_okay:	commit_creds(new);	return old_fsuid;} SYSCALL_DEFINE1(setfsuid, uid_t, uid){	return __sys_setfsuid(uid);} /* * Samma på svenska.. */long __sys_setfsgid(gid_t gid){	const struct cred *old;	struct cred *new;	gid_t old_fsgid;	kgid_t kgid; 	old = current_cred();	old_fsgid = from_kgid_munged(old->user_ns, old->fsgid); 	kgid = make_kgid(old->user_ns, gid);	if (!gid_valid(kgid))		return old_fsgid; 	new = prepare_creds();	if (!new)		return old_fsgid; 	if (gid_eq(kgid, old->gid)  || gid_eq(kgid, old->egid)  ||	    gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||	    ns_capable_setid(old->user_ns, CAP_SETGID)) {		if (!gid_eq(kgid, old->fsgid)) {			new->fsgid = kgid;			if (security_task_fix_setgid(new,old,LSM_SETID_FS) == 0)				goto change_okay;		}	} 	abort_creds(new);	return old_fsgid; change_okay:	commit_creds(new);	return old_fsgid;} SYSCALL_DEFINE1(setfsgid, gid_t, gid){	return __sys_setfsgid(gid);}#endif /* CONFIG_MULTIUSER */ /** * sys_getpid - return the thread group id of the current process * * Note, despite the name, this returns the tgid not the pid.  The tgid and * the pid are identical unless CLONE_THREAD was specified on clone() in * which case the tgid is the same in all threads of the same group. * * This is SMP safe as current->tgid does not change. */SYSCALL_DEFINE0(getpid){

Lines 501–1000 of 3074. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t