Skip to content

Commit 78ed93d

Browse files
melverPeter Zijlstra
authored andcommitted
signal: Deliver SIGTRAP on perf event asynchronously if blocked
With SIGTRAP on perf events, we have encountered termination of processes due to user space attempting to block delivery of SIGTRAP. Consider this case: <set up SIGTRAP on a perf event> ... sigset_t s; sigemptyset(&s); sigaddset(&s, SIGTRAP | <and others>); sigprocmask(SIG_BLOCK, &s, ...); ... <perf event triggers> When the perf event triggers, while SIGTRAP is blocked, force_sig_perf() will force the signal, but revert back to the default handler, thus terminating the task. This makes sense for error conditions, but not so much for explicitly requested monitoring. However, the expectation is still that signals generated by perf events are synchronous, which will no longer be the case if the signal is blocked and delivered later. To give user space the ability to clearly distinguish synchronous from asynchronous signals, introduce siginfo_t::si_perf_flags and TRAP_PERF_FLAG_ASYNC (opted for flags in case more binary information is required in future). The resolution to the problem is then to (a) no longer force the signal (avoiding the terminations), but (b) tell user space via si_perf_flags if the signal was synchronous or not, so that such signals can be handled differently (e.g. let user space decide to ignore or consider the data imprecise). The alternative of making the kernel ignore SIGTRAP on perf events if the signal is blocked may work for some usecases, but likely causes issues in others that then have to revert back to interception of sigprocmask() (which we want to avoid). [ A concrete example: when using breakpoint perf events to track data-flow, in a region of code where signals are blocked, data-flow can no longer be tracked accurately. When a relevant asynchronous signal is received after unblocking the signal, the data-flow tracking logic needs to know its state is imprecise. ] Fixes: 97ba62b ("perf: Add support for SIGTRAP on perf events") Reported-by: Dmitry Vyukov <[email protected]> Signed-off-by: Marco Elver <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Geert Uytterhoeven <[email protected]> Tested-by: Dmitry Vyukov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 7bebfe9 commit 78ed93d

File tree

12 files changed

+35
-5
lines changed

12 files changed

+35
-5
lines changed

arch/arm/kernel/signal.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ static_assert(offsetof(siginfo_t, si_upper) == 0x18);
708708
static_assert(offsetof(siginfo_t, si_pkey) == 0x14);
709709
static_assert(offsetof(siginfo_t, si_perf_data) == 0x10);
710710
static_assert(offsetof(siginfo_t, si_perf_type) == 0x14);
711+
static_assert(offsetof(siginfo_t, si_perf_flags) == 0x18);
711712
static_assert(offsetof(siginfo_t, si_band) == 0x0c);
712713
static_assert(offsetof(siginfo_t, si_fd) == 0x10);
713714
static_assert(offsetof(siginfo_t, si_call_addr) == 0x0c);

arch/arm64/kernel/signal.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,7 @@ static_assert(offsetof(siginfo_t, si_upper) == 0x28);
10111011
static_assert(offsetof(siginfo_t, si_pkey) == 0x20);
10121012
static_assert(offsetof(siginfo_t, si_perf_data) == 0x18);
10131013
static_assert(offsetof(siginfo_t, si_perf_type) == 0x20);
1014+
static_assert(offsetof(siginfo_t, si_perf_flags) == 0x24);
10141015
static_assert(offsetof(siginfo_t, si_band) == 0x10);
10151016
static_assert(offsetof(siginfo_t, si_fd) == 0x18);
10161017
static_assert(offsetof(siginfo_t, si_call_addr) == 0x10);

arch/arm64/kernel/signal32.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ static_assert(offsetof(compat_siginfo_t, si_upper) == 0x18);
487487
static_assert(offsetof(compat_siginfo_t, si_pkey) == 0x14);
488488
static_assert(offsetof(compat_siginfo_t, si_perf_data) == 0x10);
489489
static_assert(offsetof(compat_siginfo_t, si_perf_type) == 0x14);
490+
static_assert(offsetof(compat_siginfo_t, si_perf_flags) == 0x18);
490491
static_assert(offsetof(compat_siginfo_t, si_band) == 0x0c);
491492
static_assert(offsetof(compat_siginfo_t, si_fd) == 0x10);
492493
static_assert(offsetof(compat_siginfo_t, si_call_addr) == 0x0c);

arch/m68k/kernel/signal.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ static inline void siginfo_build_tests(void)
625625
/* _sigfault._perf */
626626
BUILD_BUG_ON(offsetof(siginfo_t, si_perf_data) != 0x10);
627627
BUILD_BUG_ON(offsetof(siginfo_t, si_perf_type) != 0x14);
628+
BUILD_BUG_ON(offsetof(siginfo_t, si_perf_flags) != 0x18);
628629

629630
/* _sigpoll */
630631
BUILD_BUG_ON(offsetof(siginfo_t, si_band) != 0x0c);

arch/sparc/kernel/signal32.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,5 +779,6 @@ static_assert(offsetof(compat_siginfo_t, si_upper) == 0x18);
779779
static_assert(offsetof(compat_siginfo_t, si_pkey) == 0x14);
780780
static_assert(offsetof(compat_siginfo_t, si_perf_data) == 0x10);
781781
static_assert(offsetof(compat_siginfo_t, si_perf_type) == 0x14);
782+
static_assert(offsetof(compat_siginfo_t, si_perf_flags) == 0x18);
782783
static_assert(offsetof(compat_siginfo_t, si_band) == 0x0c);
783784
static_assert(offsetof(compat_siginfo_t, si_fd) == 0x10);

arch/sparc/kernel/signal_64.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,5 +590,6 @@ static_assert(offsetof(siginfo_t, si_upper) == 0x28);
590590
static_assert(offsetof(siginfo_t, si_pkey) == 0x20);
591591
static_assert(offsetof(siginfo_t, si_perf_data) == 0x18);
592592
static_assert(offsetof(siginfo_t, si_perf_type) == 0x20);
593+
static_assert(offsetof(siginfo_t, si_perf_flags) == 0x24);
593594
static_assert(offsetof(siginfo_t, si_band) == 0x10);
594595
static_assert(offsetof(siginfo_t, si_fd) == 0x14);

arch/x86/kernel/signal_compat.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,10 @@ static inline void signal_compat_build_tests(void)
149149

150150
BUILD_BUG_ON(offsetof(siginfo_t, si_perf_data) != 0x18);
151151
BUILD_BUG_ON(offsetof(siginfo_t, si_perf_type) != 0x20);
152+
BUILD_BUG_ON(offsetof(siginfo_t, si_perf_flags) != 0x24);
152153
BUILD_BUG_ON(offsetof(compat_siginfo_t, si_perf_data) != 0x10);
153154
BUILD_BUG_ON(offsetof(compat_siginfo_t, si_perf_type) != 0x14);
155+
BUILD_BUG_ON(offsetof(compat_siginfo_t, si_perf_flags) != 0x18);
154156

155157
CHECK_CSI_OFFSET(_sigpoll);
156158
CHECK_CSI_SIZE (_sigpoll, 2*sizeof(int));

include/linux/compat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ typedef struct compat_siginfo {
235235
struct {
236236
compat_ulong_t _data;
237237
u32 _type;
238+
u32 _flags;
238239
} _perf;
239240
};
240241
} _sigfault;

include/linux/sched/signal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ int send_sig_mceerr(int code, void __user *, short, struct task_struct *);
320320

321321
int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper);
322322
int force_sig_pkuerr(void __user *addr, u32 pkey);
323-
int force_sig_perf(void __user *addr, u32 type, u64 sig_data);
323+
int send_sig_perf(void __user *addr, u32 type, u64 sig_data);
324324

325325
int force_sig_ptrace_errno_trap(int errno, void __user *addr);
326326
int force_sig_fault_trapno(int sig, int code, void __user *addr, int trapno);

include/uapi/asm-generic/siginfo.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ union __sifields {
9999
struct {
100100
unsigned long _data;
101101
__u32 _type;
102+
__u32 _flags;
102103
} _perf;
103104
};
104105
} _sigfault;
@@ -164,6 +165,7 @@ typedef struct siginfo {
164165
#define si_pkey _sifields._sigfault._addr_pkey._pkey
165166
#define si_perf_data _sifields._sigfault._perf._data
166167
#define si_perf_type _sifields._sigfault._perf._type
168+
#define si_perf_flags _sifields._sigfault._perf._flags
167169
#define si_band _sifields._sigpoll._band
168170
#define si_fd _sifields._sigpoll._fd
169171
#define si_call_addr _sifields._sigsys._call_addr
@@ -270,6 +272,11 @@ typedef struct siginfo {
270272
* that are of the form: ((PTRACE_EVENT_XXX << 8) | SIGTRAP)
271273
*/
272274

275+
/*
276+
* Flags for si_perf_flags if SIGTRAP si_code is TRAP_PERF.
277+
*/
278+
#define TRAP_PERF_FLAG_ASYNC (1u << 0)
279+
273280
/*
274281
* SIGCHLD si_codes
275282
*/

0 commit comments

Comments
 (0)