Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
[safe/jmp/linux-2.6] / kernel / sys.c
index 9968c5f..e83ddbb 100644 (file)
@@ -8,7 +8,6 @@
 #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/task_io_accounting_ops.h>
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
+#include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/fs_struct.h>
+#include <linux/gfp.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -163,6 +164,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
        if (niceval > 19)
                niceval = 19;
 
+       rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
                case PRIO_PROCESS:
@@ -190,16 +192,17 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
                                 !(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;
 }
@@ -221,6 +224,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
        if (which > PRIO_USER || which < PRIO_PROCESS)
                return -EINVAL;
 
+       rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
                case PRIO_PROCESS:
@@ -253,19 +257,20 @@ SYSCALL_DEFINE2(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;
        }
 out_unlock:
        read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        return retval;
 }
@@ -349,6 +354,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
@@ -381,7 +389,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
        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);
@@ -397,20 +405,18 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
 
        case LINUX_REBOOT_CMD_HALT:
                kernel_halt();
-               unlock_kernel();
                do_exit(0);
                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';
 
@@ -433,7 +439,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
                ret = -EINVAL;
                break;
        }
-       unlock_kernel();
+       mutex_unlock(&reboot_mutex);
        return ret;
 }
 
@@ -486,10 +492,6 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
                return -ENOMEM;
        old = current_cred();
 
-       retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
-       if (retval)
-               goto error;
-
        retval = -EPERM;
        if (rgid != (gid_t) -1) {
                if (old->gid == rgid ||
@@ -537,10 +539,6 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
                return -ENOMEM;
        old = current_cred();
 
-       retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
-       if (retval)
-               goto error;
-
        retval = -EPERM;
        if (capable(CAP_SETGID))
                new->gid = new->egid = new->sgid = new->fsgid = gid;
@@ -567,13 +565,7 @@ 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 &&
+       if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
                        new_user != INIT_USER) {
                free_uid(new_user);
                return -EAGAIN;
@@ -610,10 +602,6 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
                return -ENOMEM;
        old = current_cred();
 
-       retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
-       if (retval)
-               goto error;
-
        retval = -EPERM;
        if (ruid != (uid_t) -1) {
                new->uid = ruid;
@@ -675,10 +663,6 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
                return -ENOMEM;
        old = current_cred();
 
-       retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
-       if (retval)
-               goto error;
-
        retval = -EPERM;
        if (capable(CAP_SETUID)) {
                new->suid = new->uid = uid;
@@ -719,9 +703,6 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
        if (!new)
                return -ENOMEM;
 
-       retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
-       if (retval)
-               goto error;
        old = current_cred();
 
        retval = -EPERM;
@@ -788,10 +769,6 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
                return -ENOMEM;
        old = current_cred();
 
-       retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
-       if (retval)
-               goto error;
-
        retval = -EPERM;
        if (!capable(CAP_SETGID)) {
                if (rgid != (gid_t) -1 && rgid != old->gid &&
@@ -851,9 +828,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
        old = current_cred();
        old_fsuid = old->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)) {
@@ -864,7 +838,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
                }
        }
 
-error:
        abort_creds(new);
        return old_fsuid;
 
@@ -888,9 +861,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
        old = current_cred();
        old_fsgid = old->fsgid;
 
-       if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
-               goto error;
-
        if (gid == old->gid  || gid == old->egid  ||
            gid == old->sgid || gid == old->fsgid ||
            capable(CAP_SETGID)) {
@@ -900,7 +870,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
                }
        }
 
-error:
        abort_creds(new);
        return old_fsgid;
 
@@ -1116,6 +1085,15 @@ out:
 
 DECLARE_RWSEM(uts_sem);
 
+#ifdef COMPAT_UTS_MACHINE
+#define override_architecture(name) \
+       (personality(current->personality) == PER_LINUX32 && \
+        copy_to_user(name->machine, COMPAT_UTS_MACHINE, \
+                     sizeof(COMPAT_UTS_MACHINE)))
+#else
+#define override_architecture(name)    0
+#endif
+
 SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
 {
        int errno = 0;
@@ -1124,9 +1102,66 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
        if (copy_to_user(name, utsname(), sizeof *name))
                errno = -EFAULT;
        up_read(&uts_sem);
+
+       if (!errno && override_architecture(name))
+               errno = -EFAULT;
        return errno;
 }
 
+#ifdef __ARCH_WANT_SYS_OLD_UNAME
+/*
+ * Old cruft
+ */
+SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
+{
+       int error = 0;
+
+       if (!name)
+               return -EFAULT;
+
+       down_read(&uts_sem);
+       if (copy_to_user(name, utsname(), sizeof(*name)))
+               error = -EFAULT;
+       up_read(&uts_sem);
+
+       if (!error && override_architecture(name))
+               error = -EFAULT;
+       return error;
+}
+
+SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
+{
+       int error;
+
+       if (!name)
+               return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
+               return -EFAULT;
+
+       down_read(&uts_sem);
+       error = __copy_to_user(&name->sysname, &utsname()->sysname,
+                              __OLD_UTS_LEN);
+       error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->release, &utsname()->release,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->release + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->version, &utsname()->version,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->version + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->machine, &utsname()->machine,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->machine + __OLD_UTS_LEN);
+       up_read(&uts_sem);
+
+       if (!error && override_architecture(name))
+               error = -EFAULT;
+       return error ? -EFAULT : 0;
+}
+#endif
+
 SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
 {
        int errno;
@@ -1597,9 +1632,9 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
 
 char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
 
-static void argv_cleanup(char **argv, char **envp)
+static void argv_cleanup(struct subprocess_info *info)
 {
-       argv_free(argv);
+       argv_free(info->argv);
 }
 
 /**
@@ -1633,7 +1668,7 @@ int orderly_poweroff(bool force)
                goto out;
        }
 
-       call_usermodehelper_setcleanup(info, argv_cleanup);
+       call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL);
 
        ret = call_usermodehelper_exec(info, UMH_NO_WAIT);