vsprintf: fix %ps on non symbols when using kallsyms
[pandora-kernel.git] / kernel / sys.c
index ba0ae8e..6df4262 100644 (file)
 int overflowuid = DEFAULT_OVERFLOWUID;
 int overflowgid = DEFAULT_OVERFLOWGID;
 
-#ifdef CONFIG_UID16
 EXPORT_SYMBOL(overflowuid);
 EXPORT_SYMBOL(overflowgid);
-#endif
 
 /*
  * the same as above, but for filesystems which can only store a 16-bit
@@ -133,11 +131,10 @@ static bool set_one_prio_perm(struct task_struct *p)
 {
        const struct cred *cred = current_cred(), *pcred = __task_cred(p);
 
-       if (pcred->user->user_ns == cred->user->user_ns &&
-           (pcred->uid  == cred->euid ||
-            pcred->euid == cred->euid))
+       if (uid_eq(pcred->uid,  cred->euid) ||
+           uid_eq(pcred->euid, cred->euid))
                return true;
-       if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE))
+       if (ns_capable(pcred->user_ns, CAP_SYS_NICE))
                return true;
        return false;
 }
@@ -177,6 +174,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
        const struct cred *cred = current_cred();
        int error = -EINVAL;
        struct pid *pgrp;
+       kuid_t uid;
 
        if (which > PRIO_USER || which < PRIO_PROCESS)
                goto out;
@@ -209,18 +207,19 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
                        } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
                        break;
                case PRIO_USER:
-                       user = (struct user_struct *) cred->user;
+                       uid = make_kuid(cred->user_ns, who);
+                       user = cred->user;
                        if (!who)
-                               who = cred->uid;
-                       else if ((who != cred->uid) &&
-                                !(user = find_user(who)))
+                               uid = cred->uid;
+                       else if (!uid_eq(uid, cred->uid) &&
+                                !(user = find_user(uid)))
                                goto out_unlock;        /* No processes for this user */
 
                        do_each_thread(g, p) {
-                               if (__task_cred(p)->uid == who)
+                               if (uid_eq(task_uid(p), uid))
                                        error = set_one_prio(p, niceval, error);
                        } while_each_thread(g, p);
-                       if (who != cred->uid)
+                       if (!uid_eq(uid, cred->uid))
                                free_uid(user);         /* For find_user() */
                        break;
        }
@@ -244,6 +243,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
        const struct cred *cred = current_cred();
        long niceval, retval = -ESRCH;
        struct pid *pgrp;
+       kuid_t uid;
 
        if (which > PRIO_USER || which < PRIO_PROCESS)
                return -EINVAL;
@@ -274,21 +274,22 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
                        } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
                        break;
                case PRIO_USER:
-                       user = (struct user_struct *) cred->user;
+                       uid = make_kuid(cred->user_ns, who);
+                       user = cred->user;
                        if (!who)
-                               who = cred->uid;
-                       else if ((who != cred->uid) &&
-                                !(user = find_user(who)))
+                               uid = cred->uid;
+                       else if (!uid_eq(uid, cred->uid) &&
+                                !(user = find_user(uid)))
                                goto out_unlock;        /* No processes for this user */
 
                        do_each_thread(g, p) {
-                               if (__task_cred(p)->uid == who) {
+                               if (uid_eq(task_uid(p), uid)) {
                                        niceval = 20 - task_nice(p);
                                        if (niceval > retval)
                                                retval = niceval;
                                }
                        } while_each_thread(g, p);
-                       if (who != cred->uid)
+                       if (!uid_eq(uid, cred->uid))
                                free_uid(user);         /* for find_user() */
                        break;
        }
@@ -553,9 +554,19 @@ void ctrl_alt_del(void)
  */
 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)
@@ -564,25 +575,25 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
 
        retval = -EPERM;
        if (rgid != (gid_t) -1) {
-               if (old->gid == rgid ||
-                   old->egid == rgid ||
+               if (gid_eq(old->gid, krgid) ||
+                   gid_eq(old->egid, krgid) ||
                    nsown_capable(CAP_SETGID))
-                       new->gid = rgid;
+                       new->gid = krgid;
                else
                        goto error;
        }
        if (egid != (gid_t) -1) {
-               if (old->gid == egid ||
-                   old->egid == egid ||
-                   old->sgid == egid ||
+               if (gid_eq(old->gid, kegid) ||
+                   gid_eq(old->egid, kegid) ||
+                   gid_eq(old->sgid, kegid) ||
                    nsown_capable(CAP_SETGID))
-                       new->egid = egid;
+                       new->egid = kegid;
                else
                        goto error;
        }
 
        if (rgid != (gid_t) -1 ||
-           (egid != (gid_t) -1 && egid != old->gid))
+           (egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))
                new->sgid = new->egid;
        new->fsgid = new->egid;
 
@@ -600,9 +611,15 @@ error:
  */
 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)
@@ -611,9 +628,9 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
 
        retval = -EPERM;
        if (nsown_capable(CAP_SETGID))
-               new->gid = new->egid = new->sgid = new->fsgid = gid;
-       else if (gid == old->gid || gid == old->sgid)
-               new->egid = new->fsgid = gid;
+               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;
 
@@ -631,7 +648,7 @@ static int set_user(struct cred *new)
 {
        struct user_struct *new_user;
 
-       new_user = alloc_uid(current_user_ns(), new->uid);
+       new_user = alloc_uid(new->uid);
        if (!new_user)
                return -EAGAIN;
 
@@ -670,9 +687,19 @@ static int set_user(struct cred *new)
  */
 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)
@@ -681,29 +708,29 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
 
        retval = -EPERM;
        if (ruid != (uid_t) -1) {
-               new->uid = ruid;
-               if (old->uid != ruid &&
-                   old->euid != ruid &&
+               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 = euid;
-               if (old->uid != euid &&
-                   old->euid != euid &&
-                   old->suid != euid &&
+               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 (new->uid != old->uid) {
+       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 && euid != old->uid))
+           (euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))
                new->suid = new->euid;
        new->fsuid = new->euid;
 
@@ -731,9 +758,15 @@ error:
  */
 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)
@@ -742,17 +775,17 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
 
        retval = -EPERM;
        if (nsown_capable(CAP_SETUID)) {
-               new->suid = new->uid = uid;
-               if (uid != old->uid) {
+               new->suid = new->uid = kuid;
+               if (!uid_eq(kuid, old->uid)) {
                        retval = set_user(new);
                        if (retval < 0)
                                goto error;
                }
-       } else if (uid != old->uid && uid != new->suid) {
+       } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) {
                goto error;
        }
 
-       new->fsuid = new->euid = uid;
+       new->fsuid = new->euid = kuid;
 
        retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
        if (retval < 0)
@@ -772,9 +805,24 @@ error:
  */
 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)
@@ -784,29 +832,29 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
 
        retval = -EPERM;
        if (!nsown_capable(CAP_SETUID)) {
-               if (ruid != (uid_t) -1 && ruid != old->uid &&
-                   ruid != old->euid  && ruid != old->suid)
+               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 && euid != old->uid &&
-                   euid != old->euid  && euid != old->suid)
+               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 && suid != old->uid &&
-                   suid != old->euid  && suid != old->suid)
+               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 = ruid;
-               if (ruid != old->uid) {
+               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 = euid;
+               new->euid = keuid;
        if (suid != (uid_t) -1)
-               new->suid = suid;
+               new->suid = ksuid;
        new->fsuid = new->euid;
 
        retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
@@ -820,14 +868,19 @@ error:
        return retval;
 }
 
-SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, 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);
 
-       if (!(retval   = put_user(cred->uid,  ruid)) &&
-           !(retval   = put_user(cred->euid, euid)))
-               retval = put_user(cred->suid, suid);
+       if (!(retval   = put_user(ruid, ruidp)) &&
+           !(retval   = put_user(euid, euidp)))
+               retval = put_user(suid, suidp);
 
        return retval;
 }
@@ -837,9 +890,22 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u
  */
 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)
@@ -848,23 +914,23 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
 
        retval = -EPERM;
        if (!nsown_capable(CAP_SETGID)) {
-               if (rgid != (gid_t) -1 && rgid != old->gid &&
-                   rgid != old->egid  && rgid != old->sgid)
+               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 && egid != old->gid &&
-                   egid != old->egid  && egid != old->sgid)
+               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 && sgid != old->gid &&
-                   sgid != old->egid  && sgid != old->sgid)
+               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 = rgid;
+               new->gid = krgid;
        if (egid != (gid_t) -1)
-               new->egid = egid;
+               new->egid = kegid;
        if (sgid != (gid_t) -1)
-               new->sgid = sgid;
+               new->sgid = ksgid;
        new->fsgid = new->egid;
 
        return commit_creds(new);
@@ -874,14 +940,19 @@ error:
        return retval;
 }
 
-SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, 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);
 
-       if (!(retval   = put_user(cred->gid,  rgid)) &&
-           !(retval   = put_user(cred->egid, egid)))
-               retval = put_user(cred->sgid, sgid);
+       if (!(retval   = put_user(rgid, rgidp)) &&
+           !(retval   = put_user(egid, egidp)))
+               retval = put_user(sgid, sgidp);
 
        return retval;
 }
@@ -898,18 +969,24 @@ 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 current_fsuid();
-       old = current_cred();
-       old_fsuid = old->fsuid;
+               return old_fsuid;
 
-       if (uid == old->uid  || uid == old->euid  ||
-           uid == old->suid || uid == 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 != old_fsuid) {
-                       new->fsuid = uid;
+               if (!uid_eq(kuid, old->fsuid)) {
+                       new->fsuid = kuid;
                        if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
                                goto change_okay;
                }
@@ -931,18 +1008,24 @@ SYSCALL_DEFINE1(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 current_fsgid();
-       old = current_cred();
-       old_fsgid = old->fsgid;
+               return old_fsgid;
 
-       if (gid == old->gid  || gid == old->egid  ||
-           gid == old->sgid || gid == old->fsgid ||
+       if (gid_eq(kgid, old->gid)  || gid_eq(kgid, old->egid)  ||
+           gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
            nsown_capable(CAP_SETGID)) {
-               if (gid != old_fsgid) {
-                       new->fsgid = gid;
+               if (!gid_eq(kgid, old->fsgid)) {
+                       new->fsgid = kgid;
                        goto change_okay;
                }
        }
@@ -1498,15 +1581,14 @@ static int check_prlimit_permission(struct task_struct *task)
                return 0;
 
        tcred = __task_cred(task);
-       if (cred->user->user_ns == tcred->user->user_ns &&
-           (cred->uid == tcred->euid &&
-            cred->uid == tcred->suid &&
-            cred->uid == tcred->uid  &&
-            cred->gid == tcred->egid &&
-            cred->gid == tcred->sgid &&
-            cred->gid == tcred->gid))
+       if (uid_eq(cred->uid, tcred->euid) &&
+           uid_eq(cred->uid, tcred->suid) &&
+           uid_eq(cred->uid, tcred->uid)  &&
+           gid_eq(cred->gid, tcred->egid) &&
+           gid_eq(cred->gid, tcred->sgid) &&
+           gid_eq(cred->gid, tcred->gid))
                return 0;
-       if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE))
+       if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
                return 0;
 
        return -EPERM;