ARM: sunxi_defconfig: enable CONFIG_REGULATOR
[cascardo/linux.git] / kernel / sys.c
index ce81291..1eaa2f0 100644 (file)
 #include <asm/unistd.h>
 
 #ifndef SET_UNALIGN_CTL
-# define SET_UNALIGN_CTL(a,b)  (-EINVAL)
+# define SET_UNALIGN_CTL(a, b) (-EINVAL)
 #endif
 #ifndef GET_UNALIGN_CTL
-# define GET_UNALIGN_CTL(a,b)  (-EINVAL)
+# define GET_UNALIGN_CTL(a, b) (-EINVAL)
 #endif
 #ifndef SET_FPEMU_CTL
-# define SET_FPEMU_CTL(a,b)    (-EINVAL)
+# define SET_FPEMU_CTL(a, b)   (-EINVAL)
 #endif
 #ifndef GET_FPEMU_CTL
-# define GET_FPEMU_CTL(a,b)    (-EINVAL)
+# define GET_FPEMU_CTL(a, b)   (-EINVAL)
 #endif
 #ifndef SET_FPEXC_CTL
-# define SET_FPEXC_CTL(a,b)    (-EINVAL)
+# define SET_FPEXC_CTL(a, b)   (-EINVAL)
 #endif
 #ifndef GET_FPEXC_CTL
-# define GET_FPEXC_CTL(a,b)    (-EINVAL)
+# define GET_FPEXC_CTL(a, b)   (-EINVAL)
 #endif
 #ifndef GET_ENDIAN
-# define GET_ENDIAN(a,b)       (-EINVAL)
+# define GET_ENDIAN(a, b)      (-EINVAL)
 #endif
 #ifndef SET_ENDIAN
-# define SET_ENDIAN(a,b)       (-EINVAL)
+# define SET_ENDIAN(a, b)      (-EINVAL)
 #endif
 #ifndef GET_TSC_CTL
 # define GET_TSC_CTL(a)                (-EINVAL)
@@ -182,39 +182,40 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
        rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
-               case PRIO_PROCESS:
-                       if (who)
-                               p = find_task_by_vpid(who);
-                       else
-                               p = current;
-                       if (p)
-                               error = set_one_prio(p, niceval, error);
-                       break;
-               case PRIO_PGRP:
-                       if (who)
-                               pgrp = find_vpid(who);
-                       else
-                               pgrp = task_pgrp(current);
-                       do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
-                               error = set_one_prio(p, niceval, error);
-                       } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
-                       break;
-               case PRIO_USER:
-                       uid = make_kuid(cred->user_ns, who);
-                       user = cred->user;
-                       if (!who)
-                               uid = cred->uid;
-                       else if (!uid_eq(uid, cred->uid) &&
-                                !(user = find_user(uid)))
+       case PRIO_PROCESS:
+               if (who)
+                       p = find_task_by_vpid(who);
+               else
+                       p = current;
+               if (p)
+                       error = set_one_prio(p, niceval, error);
+               break;
+       case PRIO_PGRP:
+               if (who)
+                       pgrp = find_vpid(who);
+               else
+                       pgrp = task_pgrp(current);
+               do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
+                       error = set_one_prio(p, niceval, error);
+               } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
+               break;
+       case PRIO_USER:
+               uid = make_kuid(cred->user_ns, who);
+               user = cred->user;
+               if (!who)
+                       uid = cred->uid;
+               else if (!uid_eq(uid, cred->uid)) {
+                       user = find_user(uid);
+                       if (!user)
                                goto out_unlock;        /* No processes for this user */
-
-                       do_each_thread(g, p) {
-                               if (uid_eq(task_uid(p), uid))
-                                       error = set_one_prio(p, niceval, error);
-                       } while_each_thread(g, p);
-                       if (!uid_eq(uid, cred->uid))
-                               free_uid(user);         /* For find_user() */
-                       break;
+               }
+               do_each_thread(g, p) {
+                       if (uid_eq(task_uid(p), uid))
+                               error = set_one_prio(p, niceval, error);
+               } while_each_thread(g, p);
+               if (!uid_eq(uid, cred->uid))
+                       free_uid(user);         /* For find_user() */
+               break;
        }
 out_unlock:
        read_unlock(&tasklist_lock);
@@ -244,47 +245,48 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
        rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
-               case PRIO_PROCESS:
-                       if (who)
-                               p = find_task_by_vpid(who);
-                       else
-                               p = current;
-                       if (p) {
+       case PRIO_PROCESS:
+               if (who)
+                       p = find_task_by_vpid(who);
+               else
+                       p = current;
+               if (p) {
+                       niceval = nice_to_rlimit(task_nice(p));
+                       if (niceval > retval)
+                               retval = niceval;
+               }
+               break;
+       case PRIO_PGRP:
+               if (who)
+                       pgrp = find_vpid(who);
+               else
+                       pgrp = task_pgrp(current);
+               do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
+                       niceval = nice_to_rlimit(task_nice(p));
+                       if (niceval > retval)
+                               retval = niceval;
+               } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
+               break;
+       case PRIO_USER:
+               uid = make_kuid(cred->user_ns, who);
+               user = cred->user;
+               if (!who)
+                       uid = cred->uid;
+               else if (!uid_eq(uid, cred->uid)) {
+                       user = find_user(uid);
+                       if (!user)
+                               goto out_unlock;        /* No processes for this user */
+               }
+               do_each_thread(g, p) {
+                       if (uid_eq(task_uid(p), uid)) {
                                niceval = nice_to_rlimit(task_nice(p));
                                if (niceval > retval)
                                        retval = niceval;
                        }
-                       break;
-               case PRIO_PGRP:
-                       if (who)
-                               pgrp = find_vpid(who);
-                       else
-                               pgrp = task_pgrp(current);
-                       do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
-                               niceval = nice_to_rlimit(task_nice(p));
-                               if (niceval > retval)
-                                       retval = niceval;
-                       } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
-                       break;
-               case PRIO_USER:
-                       uid = make_kuid(cred->user_ns, who);
-                       user = cred->user;
-                       if (!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 (uid_eq(task_uid(p), uid)) {
-                                       niceval = nice_to_rlimit(task_nice(p));
-                                       if (niceval > retval)
-                                               retval = niceval;
-                               }
-                       } while_each_thread(g, p);
-                       if (!uid_eq(uid, cred->uid))
-                               free_uid(user);         /* for find_user() */
-                       break;
+               } while_each_thread(g, p);
+               if (!uid_eq(uid, cred->uid))
+                       free_uid(user);         /* for find_user() */
+               break;
        }
 out_unlock:
        read_unlock(&tasklist_lock);
@@ -306,7 +308,7 @@ out_unlock:
  *
  * The general idea is that a program which uses just setregid() will be
  * 100% compatible with BSD.  A program which uses just setgid() will be
- * 100% compatible with POSIX with saved IDs. 
+ * 100% compatible with POSIX with saved IDs.
  *
  * SMP: There are not races, the GIDs are checked only by filesystem
  *      operations (as far as semantic preservation is concerned).
@@ -364,7 +366,7 @@ error:
 }
 
 /*
- * setgid() is implemented like SysV w/ SAVED_IDS 
+ * setgid() is implemented like SysV w/ SAVED_IDS
  *
  * SMP: Same implicit races as above.
  */
@@ -442,7 +444,7 @@ static int set_user(struct cred *new)
  *
  * The general idea is that a program which uses just setreuid() will be
  * 100% compatible with BSD.  A program which uses just setuid() will be
- * 100% compatible with POSIX with saved IDs. 
+ * 100% compatible with POSIX with saved IDs.
  */
 SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
 {
@@ -503,17 +505,17 @@ error:
        abort_creds(new);
        return retval;
 }
-               
+
 /*
- * setuid() is implemented like SysV with SAVED_IDS 
- * 
+ * setuid() is implemented like SysV with SAVED_IDS
+ *
  * Note that SAVED_ID's is deficient in that a setuid root program
- * like sendmail, for example, cannot set its uid to be a normal 
+ * like sendmail, for example, cannot set its uid to be a normal
  * user and then switch back, because if you're root, setuid() sets
  * the saved uid too.  If you don't like this, blame the bright people
  * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
  * will allow a root program to temporarily drop privileges and be able to
- * regain them by swapping the real and effective uid.  
+ * regain them by swapping the real and effective uid.
  */
 SYSCALL_DEFINE1(setuid, uid_t, uid)
 {
@@ -637,10 +639,12 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t _
        euid = from_kuid_munged(cred->user_ns, cred->euid);
        suid = from_kuid_munged(cred->user_ns, cred->suid);
 
-       if (!(retval   = put_user(ruid, ruidp)) &&
-           !(retval   = put_user(euid, euidp)))
-               retval = put_user(suid, suidp);
-
+       retval = put_user(ruid, ruidp);
+       if (!retval) {
+               retval = put_user(euid, euidp);
+               if (!retval)
+                       return put_user(suid, suidp);
+       }
        return retval;
 }
 
@@ -709,9 +713,12 @@ SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t _
        egid = from_kgid_munged(cred->user_ns, cred->egid);
        sgid = from_kgid_munged(cred->user_ns, cred->sgid);
 
-       if (!(retval   = put_user(rgid, rgidp)) &&
-           !(retval   = put_user(egid, egidp)))
-               retval = put_user(sgid, sgidp);
+       retval = put_user(rgid, rgidp);
+       if (!retval) {
+               retval = put_user(egid, egidp);
+               if (!retval)
+                       retval = put_user(sgid, sgidp);
+       }
 
        return retval;
 }
@@ -862,11 +869,9 @@ void do_sys_times(struct tms *tms)
 {
        cputime_t tgutime, tgstime, cutime, cstime;
 
-       spin_lock_irq(&current->sighand->siglock);
        thread_group_cputime_adjusted(current, &tgutime, &tgstime);
        cutime = current->signal->cutime;
        cstime = current->signal->cstime;
-       spin_unlock_irq(&current->sighand->siglock);
        tms->tms_utime = cputime_to_clock_t(tgutime);
        tms->tms_stime = cputime_to_clock_t(tgstime);
        tms->tms_cutime = cputime_to_clock_t(cutime);
@@ -1284,7 +1289,6 @@ SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 /*
  *     Back compatibility for getrlimit. Needed for some apps.
  */
 SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
                struct rlimit __user *, rlim)
 {
@@ -1299,7 +1303,7 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
                x.rlim_cur = 0x7FFFFFFF;
        if (x.rlim_max > 0x7FFFFFFF)
                x.rlim_max = 0x7FFFFFFF;
-       return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0;
+       return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0;
 }
 
 #endif
@@ -1527,7 +1531,7 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
        cputime_t tgutime, tgstime, utime, stime;
        unsigned long maxrss = 0;
 
-       memset((char *) r, 0, sizeof *r);
+       memset((char *)r, 0, sizeof (*r));
        utime = stime = 0;
 
        if (who == RUSAGE_THREAD) {
@@ -1541,41 +1545,41 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                return;
 
        switch (who) {
-               case RUSAGE_BOTH:
-               case RUSAGE_CHILDREN:
-                       utime = p->signal->cutime;
-                       stime = p->signal->cstime;
-                       r->ru_nvcsw = p->signal->cnvcsw;
-                       r->ru_nivcsw = p->signal->cnivcsw;
-                       r->ru_minflt = p->signal->cmin_flt;
-                       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_adjusted(p, &tgutime, &tgstime);
-                       utime += tgutime;
-                       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);
-                       } while_each_thread(p, t);
+       case RUSAGE_BOTH:
+       case RUSAGE_CHILDREN:
+               utime = p->signal->cutime;
+               stime = p->signal->cstime;
+               r->ru_nvcsw = p->signal->cnvcsw;
+               r->ru_nivcsw = p->signal->cnivcsw;
+               r->ru_minflt = p->signal->cmin_flt;
+               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;
 
-               default:
-                       BUG();
+       case RUSAGE_SELF:
+               thread_group_cputime_adjusted(p, &tgutime, &tgstime);
+               utime += tgutime;
+               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);
+               } while_each_thread(p, t);
+               break;
+
+       default:
+               BUG();
        }
        unlock_task_sighand(p, &flags);
 
@@ -1585,6 +1589,7 @@ out:
 
        if (who != RUSAGE_CHILDREN) {
                struct mm_struct *mm = get_task_mm(p);
+
                if (mm) {
                        setmax_mm_hiwater_rss(&maxrss, mm);
                        mmput(mm);
@@ -1596,6 +1601,7 @@ out:
 int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
 {
        struct rusage r;
+
        k_getrusage(p, who, &r);
        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
 }
@@ -1628,12 +1634,14 @@ SYSCALL_DEFINE1(umask, int, mask)
        return mask;
 }
 
-static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
+static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd)
 {
        struct fd exe;
        struct inode *inode;
        int err;
 
+       VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm);
+
        exe = fdget(fd);
        if (!exe.file)
                return -EBADF;
@@ -1654,8 +1662,6 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
        if (err)
                goto exit;
 
-       down_write(&mm->mmap_sem);
-
        /*
         * Forbid mm->exe_file change if old file still mapped.
         */
@@ -1667,7 +1673,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
                        if (vma->vm_file &&
                            path_equal(&vma->vm_file->f_path,
                                       &mm->exe_file->f_path))
-                               goto exit_unlock;
+                               goto exit;
        }
 
        /*
@@ -1678,34 +1684,222 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
         */
        err = -EPERM;
        if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags))
-               goto exit_unlock;
+               goto exit;
 
        err = 0;
        set_mm_exe_file(mm, exe.file);  /* this grabs a reference to exe.file */
-exit_unlock:
-       up_write(&mm->mmap_sem);
-
 exit:
        fdput(exe);
        return err;
 }
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+/*
+ * WARNING: we don't require any capability here so be very careful
+ * in what is allowed for modification from userspace.
+ */
+static int validate_prctl_map(struct prctl_mm_map *prctl_map)
+{
+       unsigned long mmap_max_addr = TASK_SIZE;
+       struct mm_struct *mm = current->mm;
+       int error = -EINVAL, i;
+
+       static const unsigned char offsets[] = {
+               offsetof(struct prctl_mm_map, start_code),
+               offsetof(struct prctl_mm_map, end_code),
+               offsetof(struct prctl_mm_map, start_data),
+               offsetof(struct prctl_mm_map, end_data),
+               offsetof(struct prctl_mm_map, start_brk),
+               offsetof(struct prctl_mm_map, brk),
+               offsetof(struct prctl_mm_map, start_stack),
+               offsetof(struct prctl_mm_map, arg_start),
+               offsetof(struct prctl_mm_map, arg_end),
+               offsetof(struct prctl_mm_map, env_start),
+               offsetof(struct prctl_mm_map, env_end),
+       };
+
+       /*
+        * Make sure the members are not somewhere outside
+        * of allowed address space.
+        */
+       for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+               u64 val = *(u64 *)((char *)prctl_map + offsets[i]);
+
+               if ((unsigned long)val >= mmap_max_addr ||
+                   (unsigned long)val < mmap_min_addr)
+                       goto out;
+       }
+
+       /*
+        * Make sure the pairs are ordered.
+        */
+#define __prctl_check_order(__m1, __op, __m2)                          \
+       ((unsigned long)prctl_map->__m1 __op                            \
+        (unsigned long)prctl_map->__m2) ? 0 : -EINVAL
+       error  = __prctl_check_order(start_code, <, end_code);
+       error |= __prctl_check_order(start_data, <, end_data);
+       error |= __prctl_check_order(start_brk, <=, brk);
+       error |= __prctl_check_order(arg_start, <=, arg_end);
+       error |= __prctl_check_order(env_start, <=, env_end);
+       if (error)
+               goto out;
+#undef __prctl_check_order
+
+       error = -EINVAL;
+
+       /*
+        * @brk should be after @end_data in traditional maps.
+        */
+       if (prctl_map->start_brk <= prctl_map->end_data ||
+           prctl_map->brk <= prctl_map->end_data)
+               goto out;
+
+       /*
+        * Neither we should allow to override limits if they set.
+        */
+       if (check_data_rlimit(rlimit(RLIMIT_DATA), prctl_map->brk,
+                             prctl_map->start_brk, prctl_map->end_data,
+                             prctl_map->start_data))
+                       goto out;
+
+       /*
+        * Someone is trying to cheat the auxv vector.
+        */
+       if (prctl_map->auxv_size) {
+               if (!prctl_map->auxv || prctl_map->auxv_size > sizeof(mm->saved_auxv))
+                       goto out;
+       }
+
+       /*
+        * Finally, make sure the caller has the rights to
+        * change /proc/pid/exe link: only local root should
+        * be allowed to.
+        */
+       if (prctl_map->exe_fd != (u32)-1) {
+               struct user_namespace *ns = current_user_ns();
+               const struct cred *cred = current_cred();
+
+               if (!uid_eq(cred->uid, make_kuid(ns, 0)) ||
+                   !gid_eq(cred->gid, make_kgid(ns, 0)))
+                       goto out;
+       }
+
+       error = 0;
+out:
+       return error;
+}
+
+static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data_size)
+{
+       struct prctl_mm_map prctl_map = { .exe_fd = (u32)-1, };
+       unsigned long user_auxv[AT_VECTOR_SIZE];
+       struct mm_struct *mm = current->mm;
+       int error;
+
+       BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv));
+       BUILD_BUG_ON(sizeof(struct prctl_mm_map) > 256);
+
+       if (opt == PR_SET_MM_MAP_SIZE)
+               return put_user((unsigned int)sizeof(prctl_map),
+                               (unsigned int __user *)addr);
+
+       if (data_size != sizeof(prctl_map))
+               return -EINVAL;
+
+       if (copy_from_user(&prctl_map, addr, sizeof(prctl_map)))
+               return -EFAULT;
+
+       error = validate_prctl_map(&prctl_map);
+       if (error)
+               return error;
+
+       if (prctl_map.auxv_size) {
+               memset(user_auxv, 0, sizeof(user_auxv));
+               if (copy_from_user(user_auxv,
+                                  (const void __user *)prctl_map.auxv,
+                                  prctl_map.auxv_size))
+                       return -EFAULT;
+
+               /* Last entry must be AT_NULL as specification requires */
+               user_auxv[AT_VECTOR_SIZE - 2] = AT_NULL;
+               user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL;
+       }
+
+       down_write(&mm->mmap_sem);
+       if (prctl_map.exe_fd != (u32)-1)
+               error = prctl_set_mm_exe_file_locked(mm, prctl_map.exe_fd);
+       downgrade_write(&mm->mmap_sem);
+       if (error)
+               goto out;
+
+       /*
+        * We don't validate if these members are pointing to
+        * real present VMAs because application may have correspond
+        * VMAs already unmapped and kernel uses these members for statistics
+        * output in procfs mostly, except
+        *
+        *  - @start_brk/@brk which are used in do_brk but kernel lookups
+        *    for VMAs when updating these memvers so anything wrong written
+        *    here cause kernel to swear at userspace program but won't lead
+        *    to any problem in kernel itself
+        */
+
+       mm->start_code  = prctl_map.start_code;
+       mm->end_code    = prctl_map.end_code;
+       mm->start_data  = prctl_map.start_data;
+       mm->end_data    = prctl_map.end_data;
+       mm->start_brk   = prctl_map.start_brk;
+       mm->brk         = prctl_map.brk;
+       mm->start_stack = prctl_map.start_stack;
+       mm->arg_start   = prctl_map.arg_start;
+       mm->arg_end     = prctl_map.arg_end;
+       mm->env_start   = prctl_map.env_start;
+       mm->env_end     = prctl_map.env_end;
+
+       /*
+        * Note this update of @saved_auxv is lockless thus
+        * if someone reads this member in procfs while we're
+        * updating -- it may get partly updated results. It's
+        * known and acceptable trade off: we leave it as is to
+        * not introduce additional locks here making the kernel
+        * more complex.
+        */
+       if (prctl_map.auxv_size)
+               memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv));
+
+       error = 0;
+out:
+       up_read(&mm->mmap_sem);
+       return error;
+}
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
 static int prctl_set_mm(int opt, unsigned long addr,
                        unsigned long arg4, unsigned long arg5)
 {
-       unsigned long rlim = rlimit(RLIMIT_DATA);
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        int error;
 
-       if (arg5 || (arg4 && opt != PR_SET_MM_AUXV))
+       if (arg5 || (arg4 && (opt != PR_SET_MM_AUXV &&
+                             opt != PR_SET_MM_MAP &&
+                             opt != PR_SET_MM_MAP_SIZE)))
                return -EINVAL;
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+       if (opt == PR_SET_MM_MAP || opt == PR_SET_MM_MAP_SIZE)
+               return prctl_set_mm_map(opt, (const void __user *)addr, arg4);
+#endif
+
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
 
-       if (opt == PR_SET_MM_EXE_FILE)
-               return prctl_set_mm_exe_file(mm, (unsigned int)addr);
+       if (opt == PR_SET_MM_EXE_FILE) {
+               down_write(&mm->mmap_sem);
+               error = prctl_set_mm_exe_file_locked(mm, (unsigned int)addr);
+               up_write(&mm->mmap_sem);
+               return error;
+       }
 
        if (addr >= TASK_SIZE || addr < mmap_min_addr)
                return -EINVAL;
@@ -1733,9 +1927,8 @@ static int prctl_set_mm(int opt, unsigned long addr,
                if (addr <= mm->end_data)
                        goto out;
 
-               if (rlim < RLIM_INFINITY &&
-                   (mm->brk - addr) +
-                   (mm->end_data - mm->start_data) > rlim)
+               if (check_data_rlimit(rlimit(RLIMIT_DATA), mm->brk, addr,
+                                     mm->end_data, mm->start_data))
                        goto out;
 
                mm->start_brk = addr;
@@ -1745,9 +1938,8 @@ static int prctl_set_mm(int opt, unsigned long addr,
                if (addr <= mm->end_data)
                        goto out;
 
-               if (rlim < RLIM_INFINITY &&
-                   (addr - mm->start_brk) +
-                   (mm->end_data - mm->start_data) > rlim)
+               if (check_data_rlimit(rlimit(RLIMIT_DATA), addr, mm->start_brk,
+                                     mm->end_data, mm->start_data))
                        goto out;
 
                mm->brk = addr;
@@ -2023,6 +2215,7 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
 {
        int err = 0;
        int cpu = raw_smp_processor_id();
+
        if (cpup)
                err |= put_user(cpu, cpup);
        if (nodep)
@@ -2135,7 +2328,7 @@ COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info)
        /* Check to see if any memory value is too large for 32-bit and scale
         *  down if needed
         */
-       if ((s.totalram >> 32) || (s.totalswap >> 32)) {
+       if (upper_32_bits(s.totalram) || upper_32_bits(s.totalswap)) {
                int bitcount = 0;
 
                while (s.mem_unit < PAGE_SIZE) {