2240 lines · 52.0 KB · C
RawDownload
		ret = kernel_kexec();		break;#endif #ifdef CONFIG_HIBERNATION	case LINUX_REBOOT_CMD_SW_SUSPEND:		ret = hibernate();		break;#endif 	default:		ret = -EINVAL;		break;	}	mutex_unlock(&reboot_mutex);	return ret;} static void deferred_cad(struct work_struct *dummy){	kernel_restart(NULL);} /* * This function gets called by ctrl-alt-del - ie the keyboard interrupt. * As it's called within an interrupt, it may NOT sync: the only choice * is whether to reboot at once, or just ignore the ctrl-alt-del. */void ctrl_alt_del(void){	static DECLARE_WORK(cad_work, deferred_cad); 	if (C_A_D)		schedule_work(&cad_work);	else		kill_cad_pid(SIGINT, 1);}	/* * Unprivileged users may change the real gid to the effective gid * or vice versa.  (BSD-style) * * If you set the real gid at all, or set the effective gid to a value not * equal to the real gid, then the saved gid is set to the new effective gid. * * This makes it possible for a setgid 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 setregid() will be * 100% compatible with BSD.  A program which uses just setgid() will be * 100% compatible with POSIX with saved IDs.  * * SMP: There are not races, the GIDs are checked only by filesystem *      operations (as far as semantic preservation is concerned). */SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid){	struct user_namespace *ns = current_user_ns();	const struct cred *old;	struct cred *new;	int retval;	kgid_t krgid, kegid; 	krgid = make_kgid(ns, rgid);	kegid = make_kgid(ns, egid); 	if ((rgid != (gid_t) -1) && !gid_valid(krgid))		return -EINVAL;	if ((egid != (gid_t) -1) && !gid_valid(kegid))		return -EINVAL; 	new = prepare_creds();	if (!new)		return -ENOMEM;	old = current_cred(); 	retval = -EPERM;	if (rgid != (gid_t) -1) {		if (gid_eq(old->gid, krgid) ||		    gid_eq(old->egid, krgid) ||		    nsown_capable(CAP_SETGID))			new->gid = krgid;		else			goto error;	}	if (egid != (gid_t) -1) {		if (gid_eq(old->gid, kegid) ||		    gid_eq(old->egid, kegid) ||		    gid_eq(old->sgid, kegid) ||		    nsown_capable(CAP_SETGID))			new->egid = kegid;		else			goto error;	} 	if (rgid != (gid_t) -1 ||	    (egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))		new->sgid = new->egid;	new->fsgid = new->egid; 	return commit_creds(new); error:	abort_creds(new);	return retval;} /* * setgid() is implemented like SysV w/ SAVED_IDS  * * SMP: Same implicit races as above. */SYSCALL_DEFINE1(setgid, gid_t, gid){	struct user_namespace *ns = current_user_ns();	const struct cred *old;	struct cred *new;	int retval;	kgid_t kgid; 	kgid = make_kgid(ns, gid);	if (!gid_valid(kgid))		return -EINVAL; 	new = prepare_creds();	if (!new)		return -ENOMEM;	old = current_cred(); 	retval = -EPERM;	if (nsown_capable(CAP_SETGID))		new->gid = new->egid = new->sgid = new->fsgid = kgid;	else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))		new->egid = new->fsgid = kgid;	else		goto error; 	return commit_creds(new); error:	abort_creds(new);	return retval;} /* * 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; 	/*	 * 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 (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&			new_user != INIT_USER)		current->flags |= PF_NPROC_EXCEEDED;	else		current->flags &= ~PF_NPROC_EXCEEDED; 	free_uid(new->user);	new->user = new_user;	return 0;} /* * 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.  */SYSCALL_DEFINE2(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) &&		    !nsown_capable(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) &&		    !nsown_capable(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; 	return commit_creds(new); error:	abort_creds(new);	return retval;}		/* * 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.   */SYSCALL_DEFINE1(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 (nsown_capable(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; 	return commit_creds(new); error:	abort_creds(new);	return retval;}  /* * This function implements a generic ability to update ruid, euid, * and suid.  This allows you to implement the 4.4 compatible seteuid(). */SYSCALL_DEFINE3(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; 	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; 	new = prepare_creds();	if (!new)		return -ENOMEM; 	old = current_cred(); 	retval = -EPERM;	if (!nsown_capable(CAP_SETUID)) {		if (ruid != (uid_t) -1        && !uid_eq(kruid, old->uid) &&		    !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))			goto error;		if (euid != (uid_t) -1        && !uid_eq(keuid, old->uid) &&		    !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid))			goto error;		if (suid != (uid_t) -1        && !uid_eq(ksuid, old->uid) &&		    !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid))			goto error;	} 	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; 	return commit_creds(new); error:	abort_creds(new);	return retval;} 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); 	if (!(retval   = put_user(ruid, ruidp)) &&	    !(retval   = put_user(euid, euidp)))		retval = put_user(suid, suidp); 	return retval;} /* * Same as above, but for rgid, egid, sgid. */SYSCALL_DEFINE3(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; 	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; 	new = prepare_creds();	if (!new)		return -ENOMEM;	old = current_cred(); 	retval = -EPERM;	if (!nsown_capable(CAP_SETGID)) {		if (rgid != (gid_t) -1        && !gid_eq(krgid, old->gid) &&		    !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))			goto error;		if (egid != (gid_t) -1        && !gid_eq(kegid, old->gid) &&		    !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid))			goto error;		if (sgid != (gid_t) -1        && !gid_eq(ksgid, old->gid) &&		    !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid))			goto error;	} 	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; 	return commit_creds(new); error:	abort_creds(new);	return retval;} 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); 	if (!(retval   = put_user(rgid, rgidp)) &&	    !(retval   = put_user(egid, egidp)))		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.. */SYSCALL_DEFINE1(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) ||	    nsown_capable(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:

Lines 501–1000 of 2240. Previous lines