Merge branch 'linus' into locking-for-linus
[sfrench/cifs-2.6.git] / kernel / sys.c
index f145c415bc160e62b6d888cf6fa9d3198c00b4a7..37f458e6882adbd1f2b0697e5077c92e4252e03f 100644 (file)
@@ -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;