From: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> The si_perf code really wants to add a u64 field. This change enables that by reorganizing the definition of siginfo_t, so that a 64bit field can be added without increasing the alignment of other fields. Signed-off-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> --- arch/x86/kernel/signal_compat.c | 9 +++---- include/linux/compat.h | 28 +++++++++++++------- include/uapi/asm-generic/siginfo.h | 42 ++++++++++++++++++++---------- 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index a9fcabd8a5e5..a5cd01c52dfb 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -17,8 +17,6 @@ */ static inline void signal_compat_build_tests(void) { - int _sifields_offset = offsetof(compat_siginfo_t, _sifields); - /* * If adding a new si_code, there is probably new data in * the siginfo. Make sure folks bumping the si_code @@ -40,8 +38,7 @@ static inline void signal_compat_build_tests(void) * in the ABI, of course. Make sure none of them ever * move and are always at the beginning: */ - BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int)); -#define CHECK_CSI_OFFSET(name) BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name)) +#define CHECK_CSI_OFFSET(name) BUILD_BUG_ON(0 != offsetof(compat_siginfo_t, _sifields.name)) BUILD_BUG_ON(offsetof(siginfo_t, si_signo) != 0); BUILD_BUG_ON(offsetof(siginfo_t, si_errno) != 4); @@ -63,8 +60,8 @@ static inline void signal_compat_build_tests(void) * structure stays within the padding size (checked * above). */ -#define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((compat_siginfo_t *)0)->_sifields.name)) -#define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((siginfo_t *)0)->_sifields.name)) +#define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(((3*sizeof(int))+(size)) != sizeof(((compat_siginfo_t *)0)->_sifields.name)) +#define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(((4*sizeof(int))+(size)) != sizeof(((siginfo_t *)0)->_sifields.name)) CHECK_CSI_OFFSET(_kill); CHECK_CSI_SIZE (_kill, 2*sizeof(int)); diff --git a/include/linux/compat.h b/include/linux/compat.h index 6af7bef15e94..d81493248bf3 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -158,27 +158,28 @@ typedef union compat_sigval { compat_uptr_t sival_ptr; } compat_sigval_t; -typedef struct compat_siginfo { - int si_signo; -#ifndef __ARCH_HAS_SWAPPED_SIGINFO - int si_errno; - int si_code; -#else - int si_code; - int si_errno; -#endif +#define __COMPAT_SIGINFO_COMMON \ + ___SIGINFO_COMMON; \ + int _common_pad[__alignof__(compat_uptr_t) != __alignof__(int)] +typedef struct compat_siginfo { + union { + struct { + __COMPAT_SIGINFO_COMMON; + }; union { - int _pad[128/sizeof(int) - 3]; + int _pad[128/sizeof(int)]; /* kill() */ struct { + __COMPAT_SIGINFO_COMMON; compat_pid_t _pid; /* sender's pid */ __compat_uid32_t _uid; /* sender's uid */ } _kill; /* POSIX.1b timers */ struct { + __COMPAT_SIGINFO_COMMON; compat_timer_t _tid; /* timer id */ int _overrun; /* overrun count */ compat_sigval_t _sigval; /* same as below */ @@ -186,6 +187,7 @@ typedef struct compat_siginfo { /* POSIX.1b signals */ struct { + __COMPAT_SIGINFO_COMMON; compat_pid_t _pid; /* sender's pid */ __compat_uid32_t _uid; /* sender's uid */ compat_sigval_t _sigval; @@ -193,6 +195,7 @@ typedef struct compat_siginfo { /* SIGCHLD */ struct { + __COMPAT_SIGINFO_COMMON; compat_pid_t _pid; /* which child */ __compat_uid32_t _uid; /* sender's uid */ int _status; /* exit code */ @@ -203,6 +206,7 @@ typedef struct compat_siginfo { #ifdef CONFIG_X86_X32_ABI /* SIGCHLD (x32 version) */ struct { + __COMPAT_SIGINFO_COMMON; compat_pid_t _pid; /* which child */ __compat_uid32_t _uid; /* sender's uid */ int _status; /* exit code */ @@ -213,6 +217,7 @@ typedef struct compat_siginfo { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */ struct { + __COMPAT_SIGINFO_COMMON; compat_uptr_t _addr; /* faulting insn/memory ref. */ #define __COMPAT_ADDR_BND_PKEY_PAD (__alignof__(compat_uptr_t) < sizeof(short) ? \ sizeof(short) : __alignof__(compat_uptr_t)) @@ -242,16 +247,19 @@ typedef struct compat_siginfo { /* SIGPOLL */ struct { + __COMPAT_SIGINFO_COMMON; compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ int _fd; } _sigpoll; struct { + __COMPAT_SIGINFO_COMMON; compat_uptr_t _call_addr; /* calling user insn */ int _syscall; /* triggering system call number */ unsigned int _arch; /* AUDIT_ARCH_* of syscall */ } _sigsys; } _sifields; + }; } compat_siginfo_t; struct compat_rlimit { diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index e663bf117b46..1fcede623a73 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -29,15 +29,33 @@ typedef union sigval { #define __ARCH_SI_ATTRIBUTES #endif +#ifndef __ARCH_HAS_SWAPPED_SIGINFO +#define ___SIGINFO_COMMON \ + int si_signo; \ + int si_errno; \ + int si_code +#else +#define ___SIGINFO_COMMON \ + int si_signo; \ + int si_code; \ + int si_errno +#endif /* __ARCH_HAS_SWAPPED_SIGINFO */ + +#define __SIGINFO_COMMON \ + ___SIGINFO_COMMON; \ + int _common_pad[__alignof__(void *) != __alignof(int)] + union __sifields { /* kill() */ struct { + __SIGINFO_COMMON; __kernel_pid_t _pid; /* sender's pid */ __kernel_uid32_t _uid; /* sender's uid */ } _kill; /* POSIX.1b timers */ struct { + __SIGINFO_COMMON; __kernel_timer_t _tid; /* timer id */ int _overrun; /* overrun count */ sigval_t _sigval; /* same as below */ @@ -46,6 +64,7 @@ union __sifields { /* POSIX.1b signals */ struct { + __SIGINFO_COMMON; __kernel_pid_t _pid; /* sender's pid */ __kernel_uid32_t _uid; /* sender's uid */ sigval_t _sigval; @@ -53,6 +72,7 @@ union __sifields { /* SIGCHLD */ struct { + __SIGINFO_COMMON; __kernel_pid_t _pid; /* which child */ __kernel_uid32_t _uid; /* sender's uid */ int _status; /* exit code */ @@ -62,6 +82,7 @@ union __sifields { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */ struct { + __SIGINFO_COMMON; void __user *_addr; /* faulting insn/memory ref. */ #ifdef __ia64__ int _imm; /* immediate value for "break" */ @@ -97,35 +118,28 @@ union __sifields { /* SIGPOLL */ struct { + __SIGINFO_COMMON; __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ int _fd; } _sigpoll; /* SIGSYS */ struct { + __SIGINFO_COMMON; void __user *_call_addr; /* calling user insn */ int _syscall; /* triggering system call number */ unsigned int _arch; /* AUDIT_ARCH_* of syscall */ } _sigsys; }; -#ifndef __ARCH_HAS_SWAPPED_SIGINFO -#define __SIGINFO \ -struct { \ - int si_signo; \ - int si_errno; \ - int si_code; \ - union __sifields _sifields; \ -} -#else + #define __SIGINFO \ -struct { \ - int si_signo; \ - int si_code; \ - int si_errno; \ +union { \ + struct { \ + __SIGINFO_COMMON; \ + }; \ union __sifields _sifields; \ } -#endif /* __ARCH_HAS_SWAPPED_SIGINFO */ typedef struct siginfo { union { -- 2.30.1