|
@@ -559,7 +559,7 @@ error:
|
|
|
abort_creds(new);
|
|
|
return retval;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/*
|
|
|
* change the user struct in a credentials set to match the new UID
|
|
|
*/
|
|
@@ -571,6 +571,11 @@ static int set_user(struct cred *new)
|
|
|
if (!new_user)
|
|
|
return -EAGAIN;
|
|
|
|
|
|
+ if (!task_can_switch_user(new_user, current)) {
|
|
|
+ free_uid(new_user);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
if (atomic_read(&new_user->processes) >=
|
|
|
current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
|
|
|
new_user != INIT_USER) {
|
|
@@ -631,10 +636,11 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- retval = -EAGAIN;
|
|
|
- if (new->uid != old->uid && set_user(new) < 0)
|
|
|
- goto error;
|
|
|
-
|
|
|
+ if (new->uid != old->uid) {
|
|
|
+ retval = set_user(new);
|
|
|
+ if (retval < 0)
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
if (ruid != (uid_t) -1 ||
|
|
|
(euid != (uid_t) -1 && euid != old->uid))
|
|
|
new->suid = new->euid;
|
|
@@ -680,9 +686,10 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
|
|
|
retval = -EPERM;
|
|
|
if (capable(CAP_SETUID)) {
|
|
|
new->suid = new->uid = uid;
|
|
|
- if (uid != old->uid && set_user(new) < 0) {
|
|
|
- retval = -EAGAIN;
|
|
|
- goto error;
|
|
|
+ if (uid != old->uid) {
|
|
|
+ retval = set_user(new);
|
|
|
+ if (retval < 0)
|
|
|
+ goto error;
|
|
|
}
|
|
|
} else if (uid != old->uid && uid != new->suid) {
|
|
|
goto error;
|
|
@@ -734,11 +741,13 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- retval = -EAGAIN;
|
|
|
if (ruid != (uid_t) -1) {
|
|
|
new->uid = ruid;
|
|
|
- if (ruid != old->uid && set_user(new) < 0)
|
|
|
- goto error;
|
|
|
+ if (ruid != old->uid) {
|
|
|
+ retval = set_user(new);
|
|
|
+ if (retval < 0)
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
}
|
|
|
if (euid != (uid_t) -1)
|
|
|
new->euid = euid;
|