* [PATCH v2 00/20] Fix handling of compat_siginfo_t
@ 2015-11-05 0:50 Amanieu d'Antras
2015-11-05 0:50 ` [PATCH v2 02/20] compat: Add generic copy_siginfo_{to,from}_user32 Amanieu d'Antras
2015-11-08 5:09 ` [PATCH v2 00/20] Fix handling of compat_siginfo_t Andy Lutomirski
0 siblings, 2 replies; 4+ messages in thread
From: Amanieu d'Antras @ 2015-11-05 0:50 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Oleg Nesterov, Amanieu d'Antras,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-parisc-u79uwXL29TY76Z2rM5mHXA,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-s390-u79uwXL29TY76Z2rM5mHXA,
sparclinux-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-arch-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
The current handling of compat_siginfo_t is a mess: each architecture has its
own implementation, all of which are incorrect in different ways. This patch
series replaces all of the arch-specific versions with a single generic one that
is guaranteed to produce the same results as a 32-bit kernel.
Most architectures are able to use the generic compat_siginfo_t, except x86 and
MIPS. MIPS uses a slightly different compat_siginfo_t structure for ABI reasons
but can still use the generic copy_siginfo_{to,from}_user32. x86 can't use the
generic versions because it needs special handling for __SI_CHLD for x32 tasks.
One issue that isn't resolved in this series is sending signals between a 32-bit
process and 64-bit process. Sending a si_int will work correctly, but a si_ptr
value will likely get corrupted due to the different layouts of the 32-bit and
64-bit siginfo_t structures.
signalfd_copyinfo was also modified to properly generate data for compat tasks.
In particular the ssi_ptr and ssi_data members need to be sign-extended to 64
bits rather than zero-extended, since that is the behavior in 32-bit kernels.
This series has been tested on x86_64 and arm64.
Changes since v1:
- Properly copy padding bytes and avoid leaking uninitialized data to userspace
- Fixed compile errors on mips and powerpc
- Fixed some compiler warnings
- Fixed some formatting issues
Amanieu d'Antras (20):
compat: Add generic compat_siginfo_t
compat: Add generic copy_siginfo_{to,from}_user32
x86: Update compat_siginfo_t to be closer to the generic version
x86: Rewrite copy_siginfo_{to,from}_user32
mips: Clean up compat_siginfo_t
mips: Use generic copy_siginfo_{to,from}_user32
arm64: Use generic compat_siginfo_t
arm64: Use generic copy_siginfo_{to,from}_user32
parisc: Use generic compat_siginfo_t
parsic: Use generic copy_siginfo_{to,from}_user32
s390: Use generic compat_siginfo_t
s390: Use generic copy_siginfo_{to,from}_user32
powerpc: Use generic compat_siginfo_t
powerpc: Use generic copy_siginfo_{to,from}_user32
tile: Use generic compat_siginfo_t
tile: Use generic copy_siginfo_{to,from}_user32
sparc: Use generic compat_siginfo_t
sparc: Use generic copy_siginfo_{to,from}_user32
signalfd: Fix some issues in signalfd_copyinfo
signal: Remove unnecessary zero-initialization of siginfo_t
arch/arm64/include/asm/compat.h | 59 --------
arch/arm64/kernel/signal32.c | 85 -----------
arch/mips/include/asm/compat.h | 63 ++++----
arch/mips/kernel/signal32.c | 62 --------
arch/parisc/include/asm/compat.h | 52 -------
arch/parisc/kernel/signal32.c | 102 -------------
arch/powerpc/include/asm/compat.h | 60 --------
arch/powerpc/kernel/signal_32.c | 72 +---------
arch/s390/include/asm/compat.h | 51 -------
arch/s390/kernel/compat_signal.c | 102 -------------
arch/sparc/include/asm/compat.h | 54 -------
arch/sparc/kernel/signal32.c | 69 ---------
arch/tile/include/asm/compat.h | 57 --------
arch/tile/kernel/compat_signal.c | 75 ----------
arch/x86/include/asm/compat.h | 39 +++--
arch/x86/kernel/signal_compat.c | 285 ++++++++++++++++++++++++++++---------
fs/signalfd.c | 58 +++++---
include/linux/compat.h | 66 ++++++++-
include/uapi/asm-generic/siginfo.h | 1 +
kernel/compat.c | 224 +++++++++++++++++++++++++++++
kernel/ptrace.c | 1 -
kernel/signal.c | 16 ++-
22 files changed, 615 insertions(+), 1038 deletions(-)
--
2.6.2
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 02/20] compat: Add generic copy_siginfo_{to,from}_user32
2015-11-05 0:50 [PATCH v2 00/20] Fix handling of compat_siginfo_t Amanieu d'Antras
@ 2015-11-05 0:50 ` Amanieu d'Antras
2015-11-08 5:09 ` [PATCH v2 00/20] Fix handling of compat_siginfo_t Andy Lutomirski
1 sibling, 0 replies; 4+ messages in thread
From: Amanieu d'Antras @ 2015-11-05 0:50 UTC (permalink / raw)
To: linux-kernel
Cc: Oleg Nesterov, Amanieu d'Antras, Catalin Marinas, Will Deacon,
Ralf Baechle, James E.J. Bottomley, Helge Deller,
Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Martin Schwidefsky, Heiko Carstens, David S. Miller,
Chris Metcalf, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86,
Arnd Bergmann, linux-arm-kernel, linux-mips, linux-parisc,
linuxppc-dev, linux-s390, sparclinux
These routines try to match the behavior of native 32-bit kernels
as closely as possible. They will replace architecture-specific
versions that are missing support for some fields and have various
bugs that cause behavior to diverge from that of a 32-bit kernel.
The only problematic situation is when sending a si_ptr from a
32-bit process to a 64-bit process or vice-versa, but this has
never worked correctly in the past anyways.
One thing to note is that, because the size of the siginfo_t union
differs between 32-bit and 64-bit systems, we need to stash the
last 4 bytes of the union in the 4 bytes of padding between the
64-bit union and the initial 3 siginfo_t members.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
---
arch/arm64/include/asm/compat.h | 2 +
arch/mips/include/asm/compat.h | 2 +
arch/parisc/include/asm/compat.h | 2 +
arch/powerpc/include/asm/compat.h | 2 +
arch/s390/include/asm/compat.h | 2 +
arch/sparc/include/asm/compat.h | 2 +
arch/tile/include/asm/compat.h | 2 +
arch/x86/include/asm/compat.h | 2 +
include/uapi/asm-generic/siginfo.h | 1 +
kernel/compat.c | 224 +++++++++++++++++++++++++++++++++++++
kernel/signal.c | 12 +-
11 files changed, 248 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index ff4e294..5eae749 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -156,6 +156,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
typedef struct compat_siginfo {
int si_signo;
diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
index 5f1f816..1e5ba38 100644
--- a/arch/mips/include/asm/compat.h
+++ b/arch/mips/include/asm/compat.h
@@ -131,6 +131,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
#define SI_PAD_SIZE32 (128/sizeof(int) - 3)
typedef struct compat_siginfo {
diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h
index e0be05f..46a0a8a 100644
--- a/arch/parisc/include/asm/compat.h
+++ b/arch/parisc/include/asm/compat.h
@@ -135,6 +135,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
typedef struct compat_siginfo {
int si_signo;
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index 75b25ff..cdc8638 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -125,6 +125,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
#define SI_PAD_SIZE32 (128/sizeof(int) - 3)
typedef struct compat_siginfo {
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index ac73ac7..497af62 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -193,6 +193,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
typedef struct compat_siginfo {
int si_signo;
diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h
index 0c80f59..9357014 100644
--- a/arch/sparc/include/asm/compat.h
+++ b/arch/sparc/include/asm/compat.h
@@ -154,6 +154,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
#define SI_PAD_SIZE32 (128/sizeof(int) - 3)
typedef struct compat_siginfo {
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index f9bba8d..e0c61da 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -116,6 +116,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
#define COMPAT_SI_PAD_SIZE (128/sizeof(int) - 3)
typedef struct compat_siginfo {
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 69176b4..c6b58b1 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -131,6 +131,8 @@ typedef union compat_sigval {
} compat_sigval_t;
#define HAVE_ARCH_COMPAT_SIGINFO_T
+#define HAVE_ARCH_COPY_SIGINFO_TO_USER32
+#define HAVE_ARCH_COPY_SIGINFO_FROM_USER32
typedef struct compat_siginfo {
int si_signo;
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 1e35520..cc8d95e 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -49,6 +49,7 @@ typedef struct siginfo {
int si_signo;
int si_errno;
int si_code;
+ int _pad2[__ARCH_SI_PREAMBLE_SIZE / sizeof(int) - 3];
union {
int _pad[SI_PAD_SIZE];
diff --git a/kernel/compat.c b/kernel/compat.c
index 333d364..644da25 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -1174,3 +1174,227 @@ void __user *compat_alloc_user_space(unsigned long len)
return ptr;
}
EXPORT_SYMBOL_GPL(compat_alloc_user_space);
+
+#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER32
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
+{
+ int err, si_code;
+
+ if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+ return -EFAULT;
+
+ /*
+ * Get the user-visible si_code by hiding the top 16 bits if this is a
+ * kernel-generated signal.
+ */
+ si_code = from->si_code < 0 ? from->si_code : (short)from->si_code;
+
+ /*
+ * If you change siginfo_t structure, please be sure that
+ * all these functions are fixed accordingly:
+ * copy_siginfo_to_user
+ * copy_siginfo_to_user32
+ * copy_siginfo_from_user32
+ * signalfd_copyinfo
+ * They should never copy any pad contained in the structure
+ * to avoid security leaks, but must copy the generic
+ * 3 ints plus the relevant union member.
+ */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user(si_code, &to->si_code);
+ if (from->si_code < 0) {
+ /*
+ * Copy the tail bytes of the union from the padding, see the
+ * comment in copy_siginfo_from_user32. Note that this padding
+ * is always initialized when si_code < 0.
+ */
+ BUILD_BUG_ON(sizeof(to->_sifields._pad) !=
+ sizeof(from->_sifields._pad) + sizeof(from->_pad2));
+ err |= __copy_to_user(to->_sifields._pad, from->_sifields._pad,
+ sizeof(from->_sifields._pad)) ? -EFAULT : 0;
+ err |= __copy_to_user(to->_sifields._pad + SI_PAD_SIZE,
+ from->_pad2, sizeof(from->_pad2)) ? -EFAULT : 0;
+ return err;
+ }
+ switch (from->si_code & __SI_MASK) {
+ case __SI_KILL:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_TIMER:
+ err |= __put_user(from->si_tid, &to->si_tid);
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ /*
+ * Get the sigval from si_int, which matches the convention
+ * used in get_compat_sigevent.
+ */
+ err |= __put_user(from->si_int, &to->si_int);
+ break;
+ case __SI_POLL:
+ err |= __put_user(from->si_band, &to->si_band);
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ case __SI_FAULT:
+ err |= __put_user(ptr_to_compat(from->si_addr), &to->si_addr);
+#ifdef __ARCH_SI_TRAPNO
+ err |= __put_user(from->si_trapno, &to->si_trapno);
+#endif
+#ifdef BUS_MCEERR_AO
+ /*
+ * Other callers might not initialize the si_lsb field,
+ * so check explicitly for the right codes here.
+ */
+ if (from->si_signo == SIGBUS &&
+ (from->si_code == BUS_MCEERR_AR ||
+ from->si_code == BUS_MCEERR_AO))
+ err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
+#endif
+#ifdef SEGV_BNDERR
+ if (from->si_signo == SIGSEGV && from->si_code == SEGV_BNDERR) {
+ err |= __put_user(ptr_to_compat(from->si_lower),
+ &to->si_lower);
+ err |= __put_user(ptr_to_compat(from->si_upper),
+ &to->si_upper);
+ }
+#endif
+ break;
+ case __SI_CHLD:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_status, &to->si_status);
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ break;
+ case __SI_RT: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ: /* But this is */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ /*
+ * Get the sigval from si_int, which matches the convention
+ * used in get_compat_sigevent.
+ */
+ err |= __put_user(from->si_int, &to->si_int);
+ break;
+#ifdef __ARCH_SIGSYS
+ case __SI_SYS:
+ err |= __put_user(ptr_to_compat(from->si_call_addr),
+ &to->si_call_addr);
+ err |= __put_user(from->si_syscall, &to->si_syscall);
+ err |= __put_user(from->si_arch, &to->si_arch);
+ break;
+#endif
+ default: /* this is just in case for now ... */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ }
+ return err;
+}
+#endif
+
+#ifndef HAVE_ARCH_COPY_SIGINFO_FROM_USER32
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+ int err;
+ compat_uptr_t ptr32;
+
+ if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
+ return -EFAULT;
+
+ /*
+ * If you change siginfo_t structure, please be sure that
+ * all these functions are fixed accordingly:
+ * copy_siginfo_to_user
+ * copy_siginfo_to_user32
+ * copy_siginfo_from_user32
+ * signalfd_copyinfo
+ * They should never copy any pad contained in the structure
+ * to avoid security leaks, but must copy the generic
+ * 3 ints plus the relevant union member.
+ */
+ err = __get_user(to->si_signo, &from->si_signo);
+ err |= __get_user(to->si_errno, &from->si_errno);
+ err |= __get_user(to->si_code, &from->si_code);
+ if (to->si_code < 0) {
+ /*
+ * Note that the compat union may be larger than the normal one
+ * due to alignment. We work around this by copying any data
+ * that doesn't fit in the normal union into the padding before
+ * the union.
+ */
+ BUILD_BUG_ON(sizeof(to->_sifields._pad) + sizeof(to->_pad2) !=
+ sizeof(from->_sifields._pad));
+ err |= __copy_from_user(to->_sifields._pad,
+ from->_sifields._pad,
+ sizeof(to->_sifields._pad)) ? -EFAULT : 0;
+ err |= __copy_from_user(to->_pad2,
+ from->_sifields._pad + SI_PAD_SIZE, sizeof(to->_pad2))
+ ? -EFAULT : 0;
+ return err;
+ }
+ switch (to->si_code & __SI_MASK) {
+ case __SI_KILL:
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ break;
+ case __SI_TIMER:
+ err |= __get_user(to->si_tid, &from->si_tid);
+ err |= __get_user(to->si_overrun, &from->si_overrun);
+ /*
+ * Put the sigval in si_int, which matches the convention
+ * used in get_compat_sigevent.
+ */
+ to->si_ptr = NULL; /* Avoid uninitialized bits in the union */
+ err |= __get_user(to->si_int, &from->si_int);
+ break;
+ case __SI_POLL:
+ err |= __get_user(to->si_band, &from->si_band);
+ err |= __get_user(to->si_fd, &from->si_fd);
+ break;
+ case __SI_FAULT:
+ err |= __get_user(ptr32, &from->si_addr);
+ to->si_addr = compat_ptr(ptr32);
+#ifdef __ARCH_SI_TRAPNO
+ err |= __get_user(to->si_trapno, &from->si_trapno);
+#endif
+ err |= __get_user(to->si_addr_lsb, &from->si_addr_lsb);
+ err |= __get_user(ptr32, &from->si_lower);
+ to->si_lower = compat_ptr(ptr32);
+ err |= __get_user(ptr32, &from->si_upper);
+ to->si_upper = compat_ptr(ptr32);
+ break;
+ case __SI_CHLD:
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ err |= __get_user(to->si_status, &from->si_status);
+ err |= __get_user(to->si_utime, &from->si_utime);
+ err |= __get_user(to->si_stime, &from->si_stime);
+ break;
+ case __SI_RT: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ: /* But this is */
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ /*
+ * Put the sigval in si_int, which matches the convention
+ * used in get_compat_sigevent.
+ */
+ to->si_ptr = NULL; /* Avoid uninitialized bits in the union */
+ err |= __get_user(to->si_int, &from->si_int);
+ break;
+#ifdef __ARCH_SIGSYS
+ case __SI_SYS:
+ err |= __get_user(ptr32, &from->si_call_addr);
+ to->si_call_addr = compat_ptr(ptr32);
+ err |= __get_user(to->si_syscall, &from->si_syscall);
+ err |= __get_user(to->si_arch, &from->si_arch);
+ break;
+#endif
+ default: /* this is just in case for now ... */
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ break;
+ }
+ return err;
+}
+#endif
diff --git a/kernel/signal.c b/kernel/signal.c
index 0f6bbbe..873e8e2 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2713,11 +2713,13 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
return __copy_to_user(to, from, sizeof(siginfo_t))
? -EFAULT : 0;
/*
- * If you change siginfo_t structure, please be sure
- * this code is fixed accordingly.
- * Please remember to update the signalfd_copyinfo() function
- * inside fs/signalfd.c too, in case siginfo_t changes.
- * It should never copy any pad contained in the structure
+ * If you change siginfo_t structure, please be sure that
+ * all these functions are fixed accordingly:
+ * copy_siginfo_to_user
+ * copy_siginfo_to_user32
+ * copy_siginfo_from_user32
+ * signalfd_copyinfo
+ * They should never copy any pad contained in the structure
* to avoid security leaks, but must copy the generic
* 3 ints plus the relevant union member.
*/
--
2.6.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 00/20] Fix handling of compat_siginfo_t
2015-11-05 0:50 [PATCH v2 00/20] Fix handling of compat_siginfo_t Amanieu d'Antras
2015-11-05 0:50 ` [PATCH v2 02/20] compat: Add generic copy_siginfo_{to,from}_user32 Amanieu d'Antras
@ 2015-11-08 5:09 ` Andy Lutomirski
2015-11-09 15:12 ` Oleg Nesterov
1 sibling, 1 reply; 4+ messages in thread
From: Andy Lutomirski @ 2015-11-08 5:09 UTC (permalink / raw)
To: Amanieu d'Antras
Cc: linux-kernel@vger.kernel.org, Oleg Nesterov,
linux-arm-kernel@lists.infradead.org, Linux MIPS Mailing List,
linux-parisc, linuxppc-dev, linux-s390@vger.kernel.org,
sparclinux, Linux FS Devel, linux-arch, Linux API, Kenton Varda
On Wed, Nov 4, 2015 at 4:50 PM, Amanieu d'Antras <amanieu@gmail.com> wrote:
> One issue that isn't resolved in this series is sending signals between a 32-bit
> process and 64-bit process. Sending a si_int will work correctly, but a si_ptr
> value will likely get corrupted due to the different layouts of the 32-bit and
> 64-bit siginfo_t structures.
This is so screwed up it's not even funny.
A 64-bit big-endian compat calls rt_sigqueueinfo. It passes in (among
other things) a sigval_t. The kernel can choose to interpret it as a
pointer (call it p) or an integer (call it i). Then (unsigned long)p
= (i<<32) | [something]. If the number was an integer to begin with
*and* user code zeroed out the mess first, then [something] will be 0.
Regardless, p != i unless they're both zero.
If the result gets delivered to a signalfd, then it's plausible that
everything could work. If it gets delivered to a 64-bit siginfo, then
all is well because it's in exactly the same screwed up state it was
in when the signal gets sent.
If, however, it's delivered to a compat task, wtf is the kernel
supposed to do? We're effectively supposed to convert a 64-bit
sigval_t to a 32-bit sigval_t. On a little-endian architecture, we
can fudge it because it doesn't really matter whether we consider the
pointer or the int to be authoritative. I think that, on big-endian,
we're screwed.
BTW, x86 has its own set of screwups here. Somehow cr2 and error_code
ended up as part of ucontext instead of siginfo, which makes
absolutely no sense to me and bloats task_struct.
--Andy
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2 00/20] Fix handling of compat_siginfo_t
2015-11-08 5:09 ` [PATCH v2 00/20] Fix handling of compat_siginfo_t Andy Lutomirski
@ 2015-11-09 15:12 ` Oleg Nesterov
0 siblings, 0 replies; 4+ messages in thread
From: Oleg Nesterov @ 2015-11-09 15:12 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Amanieu d'Antras, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, Linux MIPS Mailing List,
linux-parisc, linuxppc-dev, linux-s390@vger.kernel.org,
sparclinux, Linux FS Devel, linux-arch, Linux API, Kenton Varda
On 11/07, Andy Lutomirski wrote:
>
> On Wed, Nov 4, 2015 at 4:50 PM, Amanieu d'Antras <amanieu@gmail.com> wrote:
> > One issue that isn't resolved in this series is sending signals between a 32-bit
> > process and 64-bit process. Sending a si_int will work correctly, but a si_ptr
> > value will likely get corrupted due to the different layouts of the 32-bit and
> > 64-bit siginfo_t structures.
>
> This is so screwed up it's not even funny.
Agreed,
> A 64-bit big-endian compat calls rt_sigqueueinfo. It passes in (among
> other things) a sigval_t. The kernel can choose to interpret it
I always thought that the kernel should not interpret it at all. And indeed,
copy_siginfo_to_user() does
if (from->si_code < 0)
return __copy_to_user(to, from, sizeof(siginfo_t))
probably copy_siginfo_to_user32() should do something similar, at least
it should not truncate ->si_code it it is less than zero.
Not sure what signalfd_copyinfo() should do.
But perhaps I was wrong, I failed to find man sigqueueinfo, and man
sigqueue() documents that it passes sigval_t.
> BTW, x86 has its own set of screwups here. Somehow cr2 and error_code
> ended up as part of ucontext instead of siginfo, which makes
> absolutely no sense to me and bloats task_struct.
Yes, and probably ->ip should have been the part of siginfo too. Say,
if you get SIGBUS you can't trust sc->ip if another signal was dequeued
before SIGBUS, in this case sc->ip will point to the handler of that
another signal. That is why we have SYNCHRONOUS_MASK and it helps, but
still this doesn't look nice.
Oleg.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2015-11-09 15:12 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-05 0:50 [PATCH v2 00/20] Fix handling of compat_siginfo_t Amanieu d'Antras
2015-11-05 0:50 ` [PATCH v2 02/20] compat: Add generic copy_siginfo_{to,from}_user32 Amanieu d'Antras
2015-11-08 5:09 ` [PATCH v2 00/20] Fix handling of compat_siginfo_t Andy Lutomirski
2015-11-09 15:12 ` Oleg Nesterov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).