CHROMIUM: s5p-mfc: fix DISPLAY_DELAY
[cascardo/linux.git] / kernel / compat.c
index f346ced..54a6f32 100644 (file)
 #include <linux/posix-timers.h>
 #include <linux/times.h>
 #include <linux/ptrace.h>
+#include <linux/prctl.h>
 #include <linux/gfp.h>
 
 #include <asm/uaccess.h>
 
 /*
- * Note that the native side is already converted to a timespec, because
- * that's what we want anyway.
+ * Get/set struct timeval with struct timespec on the native side
  */
-static int compat_get_timeval(struct timespec *o,
-               struct compat_timeval __user *i)
+static int compat_get_timeval_convert(struct timespec *o,
+                                     struct compat_timeval __user *i)
 {
        long usec;
 
@@ -46,8 +46,8 @@ static int compat_get_timeval(struct timespec *o,
        return 0;
 }
 
-static int compat_put_timeval(struct compat_timeval __user *o,
-               struct timeval *i)
+static int compat_put_timeval_convert(struct compat_timeval __user *o,
+                                     struct timeval *i)
 {
        return (put_user(i->tv_sec, &o->tv_sec) ||
                put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
@@ -117,7 +117,7 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
        if (tv) {
                struct timeval ktv;
                do_gettimeofday(&ktv);
-               if (compat_put_timeval(tv, &ktv))
+               if (compat_put_timeval_convert(tv, &ktv))
                        return -EFAULT;
        }
        if (tz) {
@@ -135,7 +135,7 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
        struct timezone ktz;
 
        if (tv) {
-               if (compat_get_timeval(&kts, tv))
+               if (compat_get_timeval_convert(&kts, tv))
                        return -EFAULT;
        }
        if (tz) {
@@ -146,12 +146,29 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
        return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
+int get_compat_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
+{
+       return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
+                       __get_user(tv->tv_sec, &ctv->tv_sec) ||
+                       __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL_GPL(get_compat_timeval);
+
+int put_compat_timeval(const struct timeval *tv, struct compat_timeval __user *ctv)
+{
+       return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) ||
+                       __put_user(tv->tv_sec, &ctv->tv_sec) ||
+                       __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL_GPL(put_compat_timeval);
+
 int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
 {
        return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
                        __get_user(ts->tv_sec, &cts->tv_sec) ||
                        __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
+EXPORT_SYMBOL_GPL(get_compat_timespec);
 
 int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
 {
@@ -161,6 +178,42 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
 }
 EXPORT_SYMBOL_GPL(put_compat_timespec);
 
+int compat_get_timeval(struct timeval *tv, const void __user *utv)
+{
+       if (COMPAT_USE_64BIT_TIME)
+               return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0;
+       else
+               return get_compat_timeval(tv, utv);
+}
+EXPORT_SYMBOL_GPL(compat_get_timeval);
+
+int compat_put_timeval(const struct timeval *tv, void __user *utv)
+{
+       if (COMPAT_USE_64BIT_TIME)
+               return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0;
+       else
+               return put_compat_timeval(tv, utv);
+}
+EXPORT_SYMBOL_GPL(compat_put_timeval);
+
+int compat_get_timespec(struct timespec *ts, const void __user *uts)
+{
+       if (COMPAT_USE_64BIT_TIME)
+               return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0;
+       else
+               return get_compat_timespec(ts, uts);
+}
+EXPORT_SYMBOL_GPL(compat_get_timespec);
+
+int compat_put_timespec(const struct timespec *ts, void __user *uts)
+{
+       if (COMPAT_USE_64BIT_TIME)
+               return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0;
+       else
+               return put_compat_timespec(ts, uts);
+}
+EXPORT_SYMBOL_GPL(compat_put_timespec);
+
 static long compat_nanosleep_restart(struct restart_block *restart)
 {
        struct compat_timespec __user *rmtp;
@@ -320,25 +373,54 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
 
 #ifdef __ARCH_WANT_SYS_SIGPROCMASK
 
-asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
-               compat_old_sigset_t __user *oset)
+/*
+ * sys_sigprocmask SIG_SETMASK sets the first (compat) word of the
+ * blocked set of signals to the supplied signal set
+ */
+static inline void compat_sig_setmask(sigset_t *blocked, compat_sigset_word set)
 {
-       old_sigset_t s;
-       long ret;
-       mm_segment_t old_fs;
+       memcpy(blocked->sig, &set, sizeof(set));
+}
 
-       if (set && get_user(s, set))
-               return -EFAULT;
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = sys_sigprocmask(how,
-                             set ? (old_sigset_t __user *) &s : NULL,
-                             oset ? (old_sigset_t __user *) &s : NULL);
-       set_fs(old_fs);
-       if (ret == 0)
-               if (oset)
-                       ret = put_user(s, oset);
-       return ret;
+asmlinkage long compat_sys_sigprocmask(int how,
+                                      compat_old_sigset_t __user *nset,
+                                      compat_old_sigset_t __user *oset)
+{
+       old_sigset_t old_set, new_set;
+       sigset_t new_blocked;
+
+       old_set = current->blocked.sig[0];
+
+       if (nset) {
+               if (get_user(new_set, nset))
+                       return -EFAULT;
+               new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
+
+               new_blocked = current->blocked;
+
+               switch (how) {
+               case SIG_BLOCK:
+                       sigaddsetmask(&new_blocked, new_set);
+                       break;
+               case SIG_UNBLOCK:
+                       sigdelsetmask(&new_blocked, new_set);
+                       break;
+               case SIG_SETMASK:
+                       compat_sig_setmask(&new_blocked, new_set);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               set_current_blocked(&new_blocked);
+       }
+
+       if (oset) {
+               if (put_user(old_set, oset))
+                       return -EFAULT;
+       }
+
+       return 0;
 }
 
 #endif
@@ -1142,6 +1224,28 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info)
        return 0;
 }
 
+/* Note: it is necessary to treat option as an unsigned int,
+ * with the corresponding cast to a signed int to ensure that the
+ * proper conversion (sign extension) between the register representation
+ * of a signed int (msr in 32-bit mode) and the register representation
+ * of a signed int (msr in 64-bit mode) is performed.
+ */
+asmlinkage long compat_sys_prctl(u32 option, u32 arg2, u32 arg3,
+                                u32 arg4, u32 arg5)
+{
+       unsigned long a2 = arg2;
+
+       /* PR_SET_PTRACER_ANY is -1, so can't do an unsigned extension */
+       if (option == PR_SET_PTRACER && arg2 == (u32) PR_SET_PTRACER_ANY)
+               a2 = PR_SET_PTRACER_ANY;
+
+       return sys_prctl((int)option,
+                        (unsigned long) a2,
+                        (unsigned long) arg3,
+                        (unsigned long) arg4,
+                        (unsigned long) arg5);
+}
+
 /*
  * Allocate user-space memory for the duration of a single system call,
  * in order to marshall parameters inside a compat thunk.