x86/signal: Add SA_{X32,IA32}_ABI sa_flags
[cascardo/linux.git] / arch / x86 / kernel / signal_compat.c
index b44564b..40df337 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/compat.h>
 #include <linux/uaccess.h>
+#include <linux/ptrace.h>
 
 /*
  * The compat_siginfo_t structure and handing code is very easy
@@ -92,10 +93,31 @@ static inline void signal_compat_build_tests(void)
        /* any new si_fields should be added here */
 }
 
-int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
+void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
+{
+       /* Don't leak in-kernel non-uapi flags to user-space */
+       if (oact)
+               oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
+
+       if (!act)
+               return;
+
+       /* Don't let flags to be set from userspace */
+       act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
+
+       if (user_64bit_mode(current_pt_regs()))
+               return;
+
+       if (in_ia32_syscall())
+               act->sa.sa_flags |= SA_IA32_ABI;
+       if (in_x32_syscall())
+               act->sa.sa_flags |= SA_X32_ABI;
+}
+
+int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
+               bool x32_ABI)
 {
        int err = 0;
-       bool ia32 = test_thread_flag(TIF_IA32);
 
        signal_compat_build_tests();
 
@@ -146,7 +168,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
                                put_user_ex(from->si_arch, &to->si_arch);
                                break;
                        case __SI_CHLD >> 16:
-                               if (ia32) {
+                               if (!x32_ABI) {
                                        put_user_ex(from->si_utime, &to->si_utime);
                                        put_user_ex(from->si_stime, &to->si_stime);
                                } else {
@@ -180,6 +202,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
        return err;
 }
 
+/* from syscall's path, where we know the ABI */
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
+{
+       return __copy_siginfo_to_user32(to, from, in_x32_syscall());
+}
+
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 {
        int err = 0;