]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/sys.c
bitops: Ensure the compile time HWEIGHT is only used for such
[linux-2.6.git] / kernel / sys.c
index ccc9eb736d35273f96422b07577fd43f5172c714..26a6b73a6b85bbc2a4ee1e1392d3aa86d1e9a850 100644 (file)
@@ -8,12 +8,12 @@
 #include <linux/mm.h>
 #include <linux/utsname.h>
 #include <linux/mman.h>
-#include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/prctl.h>
 #include <linux/highuid.h>
 #include <linux/fs.h>
+#include <linux/perf_event.h>
 #include <linux/resource.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
@@ -33,6 +33,8 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
+#include <linux/ptrace.h>
+#include <linux/fs_struct.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -142,7 +144,7 @@ out:
        return error;
 }
 
-asmlinkage long sys_setpriority(int which, int who, int niceval)
+SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
 {
        struct task_struct *g, *p;
        struct user_struct *user;
@@ -160,6 +162,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
        if (niceval > 19)
                niceval = 19;
 
+       rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
                case PRIO_PROCESS:
@@ -180,23 +183,24 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
                        } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
                        break;
                case PRIO_USER:
-                       user = cred->user;
+                       user = (struct user_struct *) cred->user;
                        if (!who)
                                who = cred->uid;
                        else if ((who != cred->uid) &&
                                 !(user = find_user(who)))
                                goto out_unlock;        /* No processes for this user */
 
-                       do_each_thread(g, p)
+                       do_each_thread(g, p) {
                                if (__task_cred(p)->uid == who)
                                        error = set_one_prio(p, niceval, error);
-                       while_each_thread(g, p);
+                       while_each_thread(g, p);
                        if (who != cred->uid)
                                free_uid(user);         /* For find_user() */
                        break;
        }
 out_unlock:
        read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 out:
        return error;
 }
@@ -207,7 +211,7 @@ out:
  * has been offset by 20 (ie it returns 40..1 instead of -20..19)
  * to stay compatible.
  */
-asmlinkage long sys_getpriority(int which, int who)
+SYSCALL_DEFINE2(getpriority, int, which, int, who)
 {
        struct task_struct *g, *p;
        struct user_struct *user;
@@ -250,13 +254,13 @@ asmlinkage long sys_getpriority(int which, int who)
                                 !(user = find_user(who)))
                                goto out_unlock;        /* No processes for this user */
 
-                       do_each_thread(g, p)
+                       do_each_thread(g, p) {
                                if (__task_cred(p)->uid == who) {
                                        niceval = 20 - task_nice(p);
                                        if (niceval > retval)
                                                retval = niceval;
                                }
-                       while_each_thread(g, p);
+                       while_each_thread(g, p);
                        if (who != cred->uid)
                                free_uid(user);         /* for find_user() */
                        break;
@@ -346,6 +350,9 @@ void kernel_power_off(void)
        machine_power_off();
 }
 EXPORT_SYMBOL_GPL(kernel_power_off);
+
+static DEFINE_MUTEX(reboot_mutex);
+
 /*
  * Reboot system call: for obvious reasons only root may call it,
  * and even root needs to set up some magic numbers in the registers
@@ -354,9 +361,11 @@ EXPORT_SYMBOL_GPL(kernel_power_off);
  *
  * reboot doesn't sync: do that yourself before calling this.
  */
-asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg)
+SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
+               void __user *, arg)
 {
        char buffer[256];
+       int ret = 0;
 
        /* We only trust the superuser with rebooting the system. */
        if (!capable(CAP_SYS_BOOT))
@@ -376,7 +385,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
        if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
                cmd = LINUX_REBOOT_CMD_HALT;
 
-       lock_kernel();
+       mutex_lock(&reboot_mutex);
        switch (cmd) {
        case LINUX_REBOOT_CMD_RESTART:
                kernel_restart(NULL);
@@ -392,20 +401,18 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
 
        case LINUX_REBOOT_CMD_HALT:
                kernel_halt();
-               unlock_kernel();
                do_exit(0);
-               break;
+               panic("cannot halt");
 
        case LINUX_REBOOT_CMD_POWER_OFF:
                kernel_power_off();
-               unlock_kernel();
                do_exit(0);
                break;
 
        case LINUX_REBOOT_CMD_RESTART2:
                if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
-                       unlock_kernel();
-                       return -EFAULT;
+                       ret = -EFAULT;
+                       break;
                }
                buffer[sizeof(buffer) - 1] = '\0';
 
@@ -414,29 +421,22 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
 
 #ifdef CONFIG_KEXEC
        case LINUX_REBOOT_CMD_KEXEC:
-               {
-                       int ret;
-                       ret = kernel_kexec();
-                       unlock_kernel();
-                       return ret;
-               }
+               ret = kernel_kexec();
+               break;
 #endif
 
 #ifdef CONFIG_HIBERNATION
        case LINUX_REBOOT_CMD_SW_SUSPEND:
-               {
-                       int ret = hibernate();
-                       unlock_kernel();
-                       return ret;
-               }
+               ret = hibernate();
+               break;
 #endif
 
        default:
-               unlock_kernel();
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
-       unlock_kernel();
-       return 0;
+       mutex_unlock(&reboot_mutex);
+       return ret;
 }
 
 static void deferred_cad(struct work_struct *dummy)
@@ -477,49 +477,50 @@ void ctrl_alt_del(void)
  * SMP: There are not races, the GIDs are checked only by filesystem
  *      operations (as far as semantic preservation is concerned).
  */
-asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
+SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
 {
-       struct cred *cred = current->cred;
-       int old_rgid = cred->gid;
-       int old_egid = cred->egid;
-       int new_rgid = old_rgid;
-       int new_egid = old_egid;
+       const struct cred *old;
+       struct cred *new;
        int retval;
 
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       old = current_cred();
+
        retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
        if (retval)
-               return retval;
+               goto error;
 
+       retval = -EPERM;
        if (rgid != (gid_t) -1) {
-               if ((old_rgid == rgid) ||
-                   (cred->egid == rgid) ||
+               if (old->gid == rgid ||
+                   old->egid == rgid ||
                    capable(CAP_SETGID))
-                       new_rgid = rgid;
+                       new->gid = rgid;
                else
-                       return -EPERM;
+                       goto error;
        }
        if (egid != (gid_t) -1) {
-               if ((old_rgid == egid) ||
-                   (cred->egid == egid) ||
-                   (cred->sgid == egid) ||
+               if (old->gid == egid ||
+                   old->egid == egid ||
+                   old->sgid == egid ||
                    capable(CAP_SETGID))
-                       new_egid = egid;
+                       new->egid = egid;
                else
-                       return -EPERM;
-       }
-       if (new_egid != old_egid) {
-               set_dumpable(current->mm, suid_dumpable);
-               smp_wmb();
+                       goto error;
        }
+
        if (rgid != (gid_t) -1 ||
-           (egid != (gid_t) -1 && egid != old_rgid))
-               cred->sgid = new_egid;
-       cred->fsgid = new_egid;
-       cred->egid = new_egid;
-       cred->gid = new_rgid;
-       key_fsgid_changed(current);
-       proc_id_connector(current, PROC_EVENT_GID);
-       return 0;
+           (egid != (gid_t) -1 && egid != old->gid))
+               new->sgid = new->egid;
+       new->fsgid = new->egid;
+
+       return commit_creds(new);
+
+error:
+       abort_creds(new);
+       return retval;
 }
 
 /*
@@ -527,59 +528,61 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
  *
  * SMP: Same implicit races as above.
  */
-asmlinkage long sys_setgid(gid_t gid)
+SYSCALL_DEFINE1(setgid, gid_t, gid)
 {
-       struct cred *cred = current->cred;
-       int old_egid = cred->egid;
+       const struct cred *old;
+       struct cred *new;
        int retval;
 
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       old = current_cred();
+
        retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
        if (retval)
-               return retval;
+               goto error;
 
-       if (capable(CAP_SETGID)) {
-               if (old_egid != gid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
-               }
-               cred->gid = cred->egid = cred->sgid = cred->fsgid = gid;
-       } else if ((gid == cred->gid) || (gid == cred->sgid)) {
-               if (old_egid != gid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
-               }
-               cred->egid = cred->fsgid = gid;
-       }
+       retval = -EPERM;
+       if (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;
        else
-               return -EPERM;
+               goto error;
 
-       key_fsgid_changed(current);
-       proc_id_connector(current, PROC_EVENT_GID);
-       return 0;
+       return commit_creds(new);
+
+error:
+       abort_creds(new);
+       return retval;
 }
-  
-static int set_user(uid_t new_ruid, int dumpclear)
+
+/*
+ * 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(current->nsproxy->user_ns, new_ruid);
+       new_user = alloc_uid(current_user_ns(), new->uid);
        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 != current->nsproxy->user_ns->root_user) {
+                       new_user != INIT_USER) {
                free_uid(new_user);
                return -EAGAIN;
        }
 
-       switch_uid(new_user);
-
-       if (dumpclear) {
-               set_dumpable(current->mm, suid_dumpable);
-               smp_wmb();
-       }
-       current->cred->uid = new_ruid;
+       free_uid(new->user);
+       new->user = new_user;
        return 0;
 }
 
@@ -598,57 +601,59 @@ static int set_user(uid_t new_ruid, int dumpclear)
  * 100% compatible with BSD.  A program which uses just setuid() will be
  * 100% compatible with POSIX with saved IDs. 
  */
-asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
+SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
 {
-       struct cred *cred = current->cred;
-       int old_ruid, old_euid, old_suid, new_ruid, new_euid;
+       const struct cred *old;
+       struct cred *new;
        int retval;
 
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       old = current_cred();
+
        retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
        if (retval)
-               return retval;
-
-       new_ruid = old_ruid = cred->uid;
-       new_euid = old_euid = cred->euid;
-       old_suid = cred->suid;
+               goto error;
 
+       retval = -EPERM;
        if (ruid != (uid_t) -1) {
-               new_ruid = ruid;
-               if ((old_ruid != ruid) &&
-                   (cred->euid != ruid) &&
+               new->uid = ruid;
+               if (old->uid != ruid &&
+                   old->euid != ruid &&
                    !capable(CAP_SETUID))
-                       return -EPERM;
+                       goto error;
        }
 
        if (euid != (uid_t) -1) {
-               new_euid = euid;
-               if ((old_ruid != euid) &&
-                   (cred->euid != euid) &&
-                   (cred->suid != euid) &&
+               new->euid = euid;
+               if (old->uid != euid &&
+                   old->euid != euid &&
+                   old->suid != euid &&
                    !capable(CAP_SETUID))
-                       return -EPERM;
+                       goto error;
        }
 
-       if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
-               return -EAGAIN;
-
-       if (new_euid != old_euid) {
-               set_dumpable(current->mm, suid_dumpable);
-               smp_wmb();
+       if (new->uid != old->uid) {
+               retval = set_user(new);
+               if (retval < 0)
+                       goto error;
        }
-       cred->fsuid = cred->euid = new_euid;
        if (ruid != (uid_t) -1 ||
-           (euid != (uid_t) -1 && euid != old_ruid))
-               cred->suid = cred->euid;
-       cred->fsuid = cred->euid;
+           (euid != (uid_t) -1 && euid != old->uid))
+               new->suid = new->euid;
+       new->fsuid = new->euid;
 
-       key_fsuid_changed(current);
-       proc_id_connector(current, PROC_EVENT_UID);
-
-       return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
-}
+       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 
@@ -661,39 +666,44 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
  * will allow a root program to temporarily drop privileges and be able to
  * regain them by swapping the real and effective uid.  
  */
-asmlinkage long sys_setuid(uid_t uid)
+SYSCALL_DEFINE1(setuid, uid_t, uid)
 {
-       struct cred *cred = current->cred;
-       int old_euid = cred->euid;
-       int old_ruid, old_suid, new_suid;
+       const struct cred *old;
+       struct cred *new;
        int retval;
 
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       old = current_cred();
+
        retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
        if (retval)
-               return retval;
+               goto error;
 
-       old_ruid = cred->uid;
-       old_suid = cred->suid;
-       new_suid = old_suid;
-       
+       retval = -EPERM;
        if (capable(CAP_SETUID)) {
-               if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
-                       return -EAGAIN;
-               new_suid = uid;
-       } else if ((uid != cred->uid) && (uid != new_suid))
-               return -EPERM;
-
-       if (old_euid != uid) {
-               set_dumpable(current->mm, suid_dumpable);
-               smp_wmb();
+               new->suid = new->uid = uid;
+               if (uid != old->uid) {
+                       retval = set_user(new);
+                       if (retval < 0)
+                               goto error;
+               }
+       } else if (uid != old->uid && uid != new->suid) {
+               goto error;
        }
-       cred->fsuid = cred->euid = uid;
-       cred->suid = new_suid;
 
-       key_fsuid_changed(current);
-       proc_id_connector(current, PROC_EVENT_UID);
+       new->fsuid = new->euid = uid;
 
-       return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
+       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;
 }
 
 
@@ -701,52 +711,60 @@ asmlinkage long sys_setuid(uid_t uid)
  * This function implements a generic ability to update ruid, euid,
  * and suid.  This allows you to implement the 4.4 compatible seteuid().
  */
-asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
 {
-       struct cred *cred = current->cred;
-       int old_ruid = cred->uid;
-       int old_euid = cred->euid;
-       int old_suid = cred->suid;
+       const struct cred *old;
+       struct cred *new;
        int retval;
 
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
        retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
        if (retval)
-               return retval;
+               goto error;
+       old = current_cred();
 
+       retval = -EPERM;
        if (!capable(CAP_SETUID)) {
-               if ((ruid != (uid_t) -1) && (ruid != cred->uid) &&
-                   (ruid != cred->euid) && (ruid != cred->suid))
-                       return -EPERM;
-               if ((euid != (uid_t) -1) && (euid != cred->uid) &&
-                   (euid != cred->euid) && (euid != cred->suid))
-                       return -EPERM;
-               if ((suid != (uid_t) -1) && (suid != cred->uid) &&
-                   (suid != cred->euid) && (suid != cred->suid))
-                       return -EPERM;
+               if (ruid != (uid_t) -1 && ruid != old->uid &&
+                   ruid != old->euid  && ruid != old->suid)
+                       goto error;
+               if (euid != (uid_t) -1 && euid != old->uid &&
+                   euid != old->euid  && euid != old->suid)
+                       goto error;
+               if (suid != (uid_t) -1 && suid != old->uid &&
+                   suid != old->euid  && suid != old->suid)
+                       goto error;
        }
+
        if (ruid != (uid_t) -1) {
-               if (ruid != cred->uid &&
-                   set_user(ruid, euid != cred->euid) < 0)
-                       return -EAGAIN;
-       }
-       if (euid != (uid_t) -1) {
-               if (euid != cred->euid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
+               new->uid = ruid;
+               if (ruid != old->uid) {
+                       retval = set_user(new);
+                       if (retval < 0)
+                               goto error;
                }
-               cred->euid = euid;
        }
-       cred->fsuid = cred->euid;
+       if (euid != (uid_t) -1)
+               new->euid = euid;
        if (suid != (uid_t) -1)
-               cred->suid = suid;
+               new->suid = suid;
+       new->fsuid = new->euid;
+
+       retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
+       if (retval < 0)
+               goto error;
 
-       key_fsuid_changed(current);
-       proc_id_connector(current, PROC_EVENT_UID);
+       return commit_creds(new);
 
-       return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
+error:
+       abort_creds(new);
+       return retval;
 }
 
-asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid)
+SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid)
 {
        const struct cred *cred = current_cred();
        int retval;
@@ -761,45 +779,50 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us
 /*
  * Same as above, but for rgid, egid, sgid.
  */
-asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
 {
-       struct cred *cred = current->cred;
+       const struct cred *old;
+       struct cred *new;
        int retval;
 
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       old = current_cred();
+
        retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
        if (retval)
-               return retval;
+               goto error;
 
+       retval = -EPERM;
        if (!capable(CAP_SETGID)) {
-               if ((rgid != (gid_t) -1) && (rgid != cred->gid) &&
-                   (rgid != cred->egid) && (rgid != cred->sgid))
-                       return -EPERM;
-               if ((egid != (gid_t) -1) && (egid != cred->gid) &&
-                   (egid != cred->egid) && (egid != cred->sgid))
-                       return -EPERM;
-               if ((sgid != (gid_t) -1) && (sgid != cred->gid) &&
-                   (sgid != cred->egid) && (sgid != cred->sgid))
-                       return -EPERM;
-       }
-       if (egid != (gid_t) -1) {
-               if (egid != cred->egid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
-               }
-               cred->egid = egid;
+               if (rgid != (gid_t) -1 && rgid != old->gid &&
+                   rgid != old->egid  && rgid != old->sgid)
+                       goto error;
+               if (egid != (gid_t) -1 && egid != old->gid &&
+                   egid != old->egid  && egid != old->sgid)
+                       goto error;
+               if (sgid != (gid_t) -1 && sgid != old->gid &&
+                   sgid != old->egid  && sgid != old->sgid)
+                       goto error;
        }
-       cred->fsgid = cred->egid;
+
        if (rgid != (gid_t) -1)
-               cred->gid = rgid;
+               new->gid = rgid;
+       if (egid != (gid_t) -1)
+               new->egid = egid;
        if (sgid != (gid_t) -1)
-               cred->sgid = sgid;
+               new->sgid = sgid;
+       new->fsgid = new->egid;
 
-       key_fsgid_changed(current);
-       proc_id_connector(current, PROC_EVENT_GID);
-       return 0;
+       return commit_creds(new);
+
+error:
+       abort_creds(new);
+       return retval;
 }
 
-asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid)
+SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid)
 {
        const struct cred *cred = current_cred();
        int retval;
@@ -818,76 +841,92 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us
  * whatever uid it wants to). It normally shadows "euid", except when
  * explicitly set by setfsuid() or for access..
  */
-asmlinkage long sys_setfsuid(uid_t uid)
+SYSCALL_DEFINE1(setfsuid, uid_t, uid)
 {
-       struct cred *cred = current->cred;
-       int old_fsuid;
+       const struct cred *old;
+       struct cred *new;
+       uid_t old_fsuid;
 
-       old_fsuid = cred->fsuid;
-       if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))
-               return old_fsuid;
+       new = prepare_creds();
+       if (!new)
+               return current_fsuid();
+       old = current_cred();
+       old_fsuid = old->fsuid;
 
-       if (uid == cred->uid || uid == cred->euid ||
-           uid == cred->suid || uid == cred->fsuid ||
+       if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
+               goto error;
+
+       if (uid == old->uid  || uid == old->euid  ||
+           uid == old->suid || uid == old->fsuid ||
            capable(CAP_SETUID)) {
                if (uid != old_fsuid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
+                       new->fsuid = uid;
+                       if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
+                               goto change_okay;
                }
-               cred->fsuid = uid;
        }
 
-       key_fsuid_changed(current);
-       proc_id_connector(current, PROC_EVENT_UID);
-
-       security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
+error:
+       abort_creds(new);
+       return old_fsuid;
 
+change_okay:
+       commit_creds(new);
        return old_fsuid;
 }
 
 /*
  * Samma pÃ¥ svenska..
  */
-asmlinkage long sys_setfsgid(gid_t gid)
+SYSCALL_DEFINE1(setfsgid, gid_t, gid)
 {
-       struct cred *cred = current->cred;
-       int old_fsgid;
+       const struct cred *old;
+       struct cred *new;
+       gid_t old_fsgid;
+
+       new = prepare_creds();
+       if (!new)
+               return current_fsgid();
+       old = current_cred();
+       old_fsgid = old->fsgid;
 
-       old_fsgid = cred->fsgid;
        if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
-               return old_fsgid;
+               goto error;
 
-       if (gid == cred->gid || gid == cred->egid ||
-           gid == cred->sgid || gid == cred->fsgid ||
+       if (gid == old->gid  || gid == old->egid  ||
+           gid == old->sgid || gid == old->fsgid ||
            capable(CAP_SETGID)) {
                if (gid != old_fsgid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
+                       new->fsgid = gid;
+                       goto change_okay;
                }
-               cred->fsgid = gid;
-               key_fsgid_changed(current);
-               proc_id_connector(current, PROC_EVENT_GID);
        }
+
+error:
+       abort_creds(new);
+       return old_fsgid;
+
+change_okay:
+       commit_creds(new);
        return old_fsgid;
 }
 
 void do_sys_times(struct tms *tms)
 {
-       struct task_cputime cputime;
-       cputime_t cutime, cstime;
+       cputime_t tgutime, tgstime, cutime, cstime;
 
        spin_lock_irq(&current->sighand->siglock);
-       thread_group_cputime(current, &cputime);
+       thread_group_times(current, &tgutime, &tgstime);
        cutime = current->signal->cutime;
        cstime = current->signal->cstime;
        spin_unlock_irq(&current->sighand->siglock);
-       tms->tms_utime = cputime_to_clock_t(cputime.utime);
-       tms->tms_stime = cputime_to_clock_t(cputime.stime);
+       tms->tms_utime = cputime_to_clock_t(tgutime);
+       tms->tms_stime = cputime_to_clock_t(tgstime);
        tms->tms_cutime = cputime_to_clock_t(cutime);
        tms->tms_cstime = cputime_to_clock_t(cstime);
 }
 
-asmlinkage long sys_times(struct tms __user * tbuf)
+SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
 {
        if (tbuf) {
                struct tms tmp;
@@ -896,6 +935,7 @@ asmlinkage long sys_times(struct tms __user * tbuf)
                if (copy_to_user(tbuf, &tmp, sizeof(struct tms)))
                        return -EFAULT;
        }
+       force_successful_syscall_return();
        return (long) jiffies_64_to_clock_t(get_jiffies_64());
 }
 
@@ -911,7 +951,7 @@ asmlinkage long sys_times(struct tms __user * tbuf)
  * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
  * LBT 04.03.94
  */
-asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
+SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)
 {
        struct task_struct *p;
        struct task_struct *group_leader = current->group_leader;
@@ -970,10 +1010,8 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
        if (err)
                goto out;
 
-       if (task_pgrp(p) != pgrp) {
+       if (task_pgrp(p) != pgrp)
                change_pid(p, PIDTYPE_PGID, pgrp);
-               set_task_pgrp(p, pid_nr(pgrp));
-       }
 
        err = 0;
 out:
@@ -982,7 +1020,7 @@ out:
        return err;
 }
 
-asmlinkage long sys_getpgid(pid_t pid)
+SYSCALL_DEFINE1(getpgid, pid_t, pid)
 {
        struct task_struct *p;
        struct pid *grp;
@@ -1012,14 +1050,14 @@ out:
 
 #ifdef __ARCH_WANT_SYS_GETPGRP
 
-asmlinkage long sys_getpgrp(void)
+SYSCALL_DEFINE0(getpgrp)
 {
        return sys_getpgid(0);
 }
 
 #endif
 
-asmlinkage long sys_getsid(pid_t pid)
+SYSCALL_DEFINE1(getsid, pid_t, pid)
 {
        struct task_struct *p;
        struct pid *sid;
@@ -1047,7 +1085,7 @@ out:
        return retval;
 }
 
-asmlinkage long sys_setsid(void)
+SYSCALL_DEFINE0(setsid)
 {
        struct task_struct *group_leader = current->group_leader;
        struct pid *sid = task_pid(group_leader);
@@ -1073,288 +1111,14 @@ asmlinkage long sys_setsid(void)
        err = session;
 out:
        write_unlock_irq(&tasklist_lock);
+       if (err > 0)
+               proc_sid_connector(group_leader);
        return err;
 }
 
-/*
- * Supplementary group IDs
- */
-
-/* init to 2 - one for init_task, one to ensure it is never freed */
-struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
-
-struct group_info *groups_alloc(int gidsetsize)
-{
-       struct group_info *group_info;
-       int nblocks;
-       int i;
-
-       nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK;
-       /* Make sure we always allocate at least one indirect block pointer */
-       nblocks = nblocks ? : 1;
-       group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
-       if (!group_info)
-               return NULL;
-       group_info->ngroups = gidsetsize;
-       group_info->nblocks = nblocks;
-       atomic_set(&group_info->usage, 1);
-
-       if (gidsetsize <= NGROUPS_SMALL)
-               group_info->blocks[0] = group_info->small_block;
-       else {
-               for (i = 0; i < nblocks; i++) {
-                       gid_t *b;
-                       b = (void *)__get_free_page(GFP_USER);
-                       if (!b)
-                               goto out_undo_partial_alloc;
-                       group_info->blocks[i] = b;
-               }
-       }
-       return group_info;
-
-out_undo_partial_alloc:
-       while (--i >= 0) {
-               free_page((unsigned long)group_info->blocks[i]);
-       }
-       kfree(group_info);
-       return NULL;
-}
-
-EXPORT_SYMBOL(groups_alloc);
-
-void groups_free(struct group_info *group_info)
-{
-       if (group_info->blocks[0] != group_info->small_block) {
-               int i;
-               for (i = 0; i < group_info->nblocks; i++)
-                       free_page((unsigned long)group_info->blocks[i]);
-       }
-       kfree(group_info);
-}
-
-EXPORT_SYMBOL(groups_free);
-
-/* export the group_info to a user-space array */
-static int groups_to_user(gid_t __user *grouplist,
-    struct group_info *group_info)
-{
-       int i;
-       unsigned int count = group_info->ngroups;
-
-       for (i = 0; i < group_info->nblocks; i++) {
-               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
-               unsigned int len = cp_count * sizeof(*grouplist);
-
-               if (copy_to_user(grouplist, group_info->blocks[i], len))
-                       return -EFAULT;
-
-               grouplist += NGROUPS_PER_BLOCK;
-               count -= cp_count;
-       }
-       return 0;
-}
-
-/* fill a group_info from a user-space array - it must be allocated already */
-static int groups_from_user(struct group_info *group_info,
-    gid_t __user *grouplist)
-{
-       int i;
-       unsigned int count = group_info->ngroups;
-
-       for (i = 0; i < group_info->nblocks; i++) {
-               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
-               unsigned int len = cp_count * sizeof(*grouplist);
-
-               if (copy_from_user(group_info->blocks[i], grouplist, len))
-                       return -EFAULT;
-
-               grouplist += NGROUPS_PER_BLOCK;
-               count -= cp_count;
-       }
-       return 0;
-}
-
-/* a simple Shell sort */
-static void groups_sort(struct group_info *group_info)
-{
-       int base, max, stride;
-       int gidsetsize = group_info->ngroups;
-
-       for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
-               ; /* nothing */
-       stride /= 3;
-
-       while (stride) {
-               max = gidsetsize - stride;
-               for (base = 0; base < max; base++) {
-                       int left = base;
-                       int right = left + stride;
-                       gid_t tmp = GROUP_AT(group_info, right);
-
-                       while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
-                               GROUP_AT(group_info, right) =
-                                   GROUP_AT(group_info, left);
-                               right = left;
-                               left -= stride;
-                       }
-                       GROUP_AT(group_info, right) = tmp;
-               }
-               stride /= 3;
-       }
-}
-
-/* a simple bsearch */
-int groups_search(const struct group_info *group_info, gid_t grp)
-{
-       unsigned int left, right;
-
-       if (!group_info)
-               return 0;
-
-       left = 0;
-       right = group_info->ngroups;
-       while (left < right) {
-               unsigned int mid = (left+right)/2;
-               int cmp = grp - GROUP_AT(group_info, mid);
-               if (cmp > 0)
-                       left = mid + 1;
-               else if (cmp < 0)
-                       right = mid;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * set_groups - Change a group subscription in a security record
- * @sec: The security record to alter
- * @group_info: The group list to impose
- *
- * Validate a group subscription and, if valid, impose it upon a task security
- * record.
- */
-int set_groups(struct cred *cred, struct group_info *group_info)
-{
-       int retval;
-       struct group_info *old_info;
-
-       retval = security_task_setgroups(group_info);
-       if (retval)
-               return retval;
-
-       groups_sort(group_info);
-       get_group_info(group_info);
-
-       spin_lock(&cred->lock);
-       old_info = cred->group_info;
-       cred->group_info = group_info;
-       spin_unlock(&cred->lock);
-
-       put_group_info(old_info);
-       return 0;
-}
-
-EXPORT_SYMBOL(set_groups);
-
-/**
- * set_current_groups - Change current's group subscription
- * @group_info: The group list to impose
- *
- * Validate a group subscription and, if valid, impose it upon current's task
- * security record.
- */
-int set_current_groups(struct group_info *group_info)
-{
-       return set_groups(current->cred, group_info);
-}
-
-EXPORT_SYMBOL(set_current_groups);
-
-asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
-{
-       const struct cred *cred = current_cred();
-       int i;
-
-       if (gidsetsize < 0)
-               return -EINVAL;
-
-       /* no need to grab task_lock here; it cannot change */
-       i = cred->group_info->ngroups;
-       if (gidsetsize) {
-               if (i > gidsetsize) {
-                       i = -EINVAL;
-                       goto out;
-               }
-               if (groups_to_user(grouplist, cred->group_info)) {
-                       i = -EFAULT;
-                       goto out;
-               }
-       }
-out:
-       return i;
-}
-
-/*
- *     SMP: Our groups are copy-on-write. We can set them safely
- *     without another task interfering.
- */
-asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
-{
-       struct group_info *group_info;
-       int retval;
-
-       if (!capable(CAP_SETGID))
-               return -EPERM;
-       if ((unsigned)gidsetsize > NGROUPS_MAX)
-               return -EINVAL;
-
-       group_info = groups_alloc(gidsetsize);
-       if (!group_info)
-               return -ENOMEM;
-       retval = groups_from_user(group_info, grouplist);
-       if (retval) {
-               put_group_info(group_info);
-               return retval;
-       }
-
-       retval = set_current_groups(group_info);
-       put_group_info(group_info);
-
-       return retval;
-}
-
-/*
- * Check whether we're fsgid/egid or in the supplemental group..
- */
-int in_group_p(gid_t grp)
-{
-       const struct cred *cred = current_cred();
-       int retval = 1;
-
-       if (grp != cred->fsgid)
-               retval = groups_search(cred->group_info, grp);
-       return retval;
-}
-
-EXPORT_SYMBOL(in_group_p);
-
-int in_egroup_p(gid_t grp)
-{
-       const struct cred *cred = current_cred();
-       int retval = 1;
-
-       if (grp != cred->egid)
-               retval = groups_search(cred->group_info, grp);
-       return retval;
-}
-
-EXPORT_SYMBOL(in_egroup_p);
-
 DECLARE_RWSEM(uts_sem);
 
-asmlinkage long sys_newuname(struct new_utsname __user * name)
+SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
 {
        int errno = 0;
 
@@ -1365,7 +1129,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name)
        return errno;
 }
 
-asmlinkage long sys_sethostname(char __user *name, int len)
+SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
 {
        int errno;
        char tmp[__NEW_UTS_LEN];
@@ -1389,7 +1153,7 @@ asmlinkage long sys_sethostname(char __user *name, int len)
 
 #ifdef __ARCH_WANT_SYS_GETHOSTNAME
 
-asmlinkage long sys_gethostname(char __user *name, int len)
+SYSCALL_DEFINE2(gethostname, char __user *, name, int, len)
 {
        int i, errno;
        struct new_utsname *u;
@@ -1414,7 +1178,7 @@ asmlinkage long sys_gethostname(char __user *name, int len)
  * Only setdomainname; getdomainname can be implemented by calling
  * uname()
  */
-asmlinkage long sys_setdomainname(char __user *name, int len)
+SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
 {
        int errno;
        char tmp[__NEW_UTS_LEN];
@@ -1437,7 +1201,7 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
        return errno;
 }
 
-asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim)
+SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 {
        if (resource >= RLIM_NLIMITS)
                return -EINVAL;
@@ -1456,7 +1220,8 @@ asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim)
  *     Back compatibility for getrlimit. Needed for some apps.
  */
  
-asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim)
+SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
+               struct rlimit __user *, rlim)
 {
        struct rlimit x;
        if (resource >= RLIM_NLIMITS)
@@ -1474,7 +1239,7 @@ asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *r
 
 #endif
 
-asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
+SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 {
        struct rlimit new_rlim, *old_rlim;
        int retval;
@@ -1483,22 +1248,14 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
                return -EINVAL;
        if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
                return -EFAULT;
+       if (new_rlim.rlim_cur > new_rlim.rlim_max)
+               return -EINVAL;
        old_rlim = current->signal->rlim + resource;
        if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
            !capable(CAP_SYS_RESOURCE))
                return -EPERM;
-
-       if (resource == RLIMIT_NOFILE) {
-               if (new_rlim.rlim_max == RLIM_INFINITY)
-                       new_rlim.rlim_max = sysctl_nr_open;
-               if (new_rlim.rlim_cur == RLIM_INFINITY)
-                       new_rlim.rlim_cur = sysctl_nr_open;
-               if (new_rlim.rlim_max > sysctl_nr_open)
-                       return -EPERM;
-       }
-
-       if (new_rlim.rlim_cur > new_rlim.rlim_max)
-               return -EINVAL;
+       if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
+               return -EPERM;
 
        retval = security_task_setrlimit(resource, &new_rlim);
        if (retval)
@@ -1582,14 +1339,16 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
 {
        struct task_struct *t;
        unsigned long flags;
-       cputime_t utime, stime;
-       struct task_cputime cputime;
+       cputime_t tgutime, tgstime, utime, stime;
+       unsigned long maxrss = 0;
 
        memset((char *) r, 0, sizeof *r);
        utime = stime = cputime_zero;
 
        if (who == RUSAGE_THREAD) {
+               task_times(current, &utime, &stime);
                accumulate_thread_rusage(p, r);
+               maxrss = p->signal->maxrss;
                goto out;
        }
 
@@ -1607,20 +1366,23 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                        r->ru_majflt = p->signal->cmaj_flt;
                        r->ru_inblock = p->signal->cinblock;
                        r->ru_oublock = p->signal->coublock;
+                       maxrss = p->signal->cmaxrss;
 
                        if (who == RUSAGE_CHILDREN)
                                break;
 
                case RUSAGE_SELF:
-                       thread_group_cputime(p, &cputime);
-                       utime = cputime_add(utime, cputime.utime);
-                       stime = cputime_add(stime, cputime.stime);
+                       thread_group_times(p, &tgutime, &tgstime);
+                       utime = cputime_add(utime, tgutime);
+                       stime = cputime_add(stime, tgstime);
                        r->ru_nvcsw += p->signal->nvcsw;
                        r->ru_nivcsw += p->signal->nivcsw;
                        r->ru_minflt += p->signal->min_flt;
                        r->ru_majflt += p->signal->maj_flt;
                        r->ru_inblock += p->signal->inblock;
                        r->ru_oublock += p->signal->oublock;
+                       if (maxrss < p->signal->maxrss)
+                               maxrss = p->signal->maxrss;
                        t = p;
                        do {
                                accumulate_thread_rusage(t, r);
@@ -1636,6 +1398,15 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
 out:
        cputime_to_timeval(utime, &r->ru_utime);
        cputime_to_timeval(stime, &r->ru_stime);
+
+       if (who != RUSAGE_CHILDREN) {
+               struct mm_struct *mm = get_task_mm(p);
+               if (mm) {
+                       setmax_mm_hiwater_rss(&maxrss, mm);
+                       mmput(mm);
+               }
+       }
+       r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */
 }
 
 int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
@@ -1645,7 +1416,7 @@ int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
 }
 
-asmlinkage long sys_getrusage(int who, struct rusage __user *ru)
+SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru)
 {
        if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN &&
            who != RUSAGE_THREAD)
@@ -1653,22 +1424,24 @@ asmlinkage long sys_getrusage(int who, struct rusage __user *ru)
        return getrusage(current, who, ru);
 }
 
-asmlinkage long sys_umask(int mask)
+SYSCALL_DEFINE1(umask, int, mask)
 {
        mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
        return mask;
 }
 
-asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
-                         unsigned long arg4, unsigned long arg5)
+SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
+               unsigned long, arg4, unsigned long, arg5)
 {
        struct task_struct *me = current;
        unsigned char comm[sizeof(me->comm)];
        long error;
 
-       if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
+       error = security_task_prctl(option, arg2, arg3, arg4, arg5);
+       if (error != -ENOSYS)
                return error;
 
+       error = 0;
        switch (option) {
                case PR_SET_PDEATHSIG:
                        if (!valid_signal(arg2)) {
@@ -1753,6 +1526,12 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                case PR_SET_TSC:
                        error = SET_TSC_CTL(arg2);
                        break;
+               case PR_TASK_PERF_EVENTS_DISABLE:
+                       error = perf_event_task_disable();
+                       break;
+               case PR_TASK_PERF_EVENTS_ENABLE:
+                       error = perf_event_task_enable();
+                       break;
                case PR_GET_TIMERSLACK:
                        error = current->timer_slack_ns;
                        break;
@@ -1764,6 +1543,41 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                                current->timer_slack_ns = arg2;
                        error = 0;
                        break;
+               case PR_MCE_KILL:
+                       if (arg4 | arg5)
+                               return -EINVAL;
+                       switch (arg2) {
+                       case PR_MCE_KILL_CLEAR:
+                               if (arg3 != 0)
+                                       return -EINVAL;
+                               current->flags &= ~PF_MCE_PROCESS;
+                               break;
+                       case PR_MCE_KILL_SET:
+                               current->flags |= PF_MCE_PROCESS;
+                               if (arg3 == PR_MCE_KILL_EARLY)
+                                       current->flags |= PF_MCE_EARLY;
+                               else if (arg3 == PR_MCE_KILL_LATE)
+                                       current->flags &= ~PF_MCE_EARLY;
+                               else if (arg3 == PR_MCE_KILL_DEFAULT)
+                                       current->flags &=
+                                               ~(PF_MCE_EARLY|PF_MCE_PROCESS);
+                               else
+                                       return -EINVAL;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       error = 0;
+                       break;
+               case PR_MCE_KILL_GET:
+                       if (arg2 | arg3 | arg4 | arg5)
+                               return -EINVAL;
+                       if (current->flags & PF_MCE_PROCESS)
+                               error = (current->flags & PF_MCE_EARLY) ?
+                                       PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE;
+                       else
+                               error = PR_MCE_KILL_DEFAULT;
+                       break;
                default:
                        error = -EINVAL;
                        break;
@@ -1771,8 +1585,8 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
        return error;
 }
 
-asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep,
-                          struct getcpu_cache __user *unused)
+SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
+               struct getcpu_cache __user *, unused)
 {
        int err = 0;
        int cpu = raw_smp_processor_id();