Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

signal: define the SA_EXPOSE_TAGBITS bit in sa_flags

Architectures that support address tagging, such as arm64, may want to
expose fault address tag bits to the signal handler to help diagnose
memory errors. However, these bits have not been previously set,
and their presence may confuse unaware user applications. Therefore,
introduce a SA_EXPOSE_TAGBITS flag bit in sa_flags that a signal
handler may use to explicitly request that the bits are set.

The generic signal handler APIs expect to receive tagged addresses.
Architectures may specify how to untag addresses in the case where
SA_EXPOSE_TAGBITS is clear by defining the arch_untagged_si_addr
function.

Signed-off-by: Peter Collingbourne <pcc@google.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Link: https://linux-review.googlesource.com/id/I16dd0ed2081f091fce97be0190cb8caa874c26cb
Link: https://lkml.kernel.org/r/13cf24d00ebdd8e1f55caf1821c7c29d54100191.1605904350.git.pcc@google.com
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

authored by

Peter Collingbourne and committed by
Eric W. Biederman
6ac05e83 a54f0dfd

+42 -1
+14
include/linux/signal.h
··· 469 469 extern void render_sigset_t(struct seq_file *, const char *, sigset_t *); 470 470 #endif 471 471 472 + #ifndef arch_untagged_si_addr 473 + /* 474 + * Given a fault address and a signal and si_code which correspond to the 475 + * _sigfault union member, returns the address that must appear in si_addr if 476 + * the signal handler does not have SA_EXPOSE_TAGBITS enabled in sa_flags. 477 + */ 478 + static inline void __user *arch_untagged_si_addr(void __user *addr, 479 + unsigned long sig, 480 + unsigned long si_code) 481 + { 482 + return addr; 483 + } 484 + #endif 485 + 472 486 #endif /* _LINUX_SIGNAL_H */
+1 -1
include/linux/signal_types.h
··· 78 78 79 79 #define UAPI_SA_FLAGS \ 80 80 (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ 81 - SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) 81 + SA_NODEFER | SA_RESETHAND | SA_EXPOSE_TAGBITS | __ARCH_UAPI_SA_FLAGS) 82 82 83 83 #endif /* _LINUX_SIGNAL_TYPES_H */
+3
include/uapi/asm-generic/signal-defs.h
··· 20 20 * so this bit allows flag bit support to be detected from userspace while 21 21 * allowing an old kernel to be distinguished from a kernel that supports every 22 22 * flag bit. 23 + * SA_EXPOSE_TAGBITS exposes an architecture-defined set of tag bits in 24 + * siginfo.si_addr. 23 25 * 24 26 * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single 25 27 * Unix names RESETHAND and NODEFER respectively. ··· 43 41 /* 0x00000100 used on sparc */ 44 42 /* 0x00000200 used on sparc */ 45 43 #define SA_UNSUPPORTED 0x00000400 44 + #define SA_EXPOSE_TAGBITS 0x00000800 46 45 /* 0x00010000 used on mips */ 47 46 /* 0x01000000 used on x86 */ 48 47 /* 0x02000000 used on x86 */
+24
kernel/signal.c
··· 2524 2524 return signr; 2525 2525 } 2526 2526 2527 + static void hide_si_addr_tag_bits(struct ksignal *ksig) 2528 + { 2529 + switch (siginfo_layout(ksig->sig, ksig->info.si_code)) { 2530 + case SIL_FAULT: 2531 + case SIL_FAULT_MCEERR: 2532 + case SIL_FAULT_BNDERR: 2533 + case SIL_FAULT_PKUERR: 2534 + ksig->info.si_addr = arch_untagged_si_addr( 2535 + ksig->info.si_addr, ksig->sig, ksig->info.si_code); 2536 + break; 2537 + case SIL_KILL: 2538 + case SIL_TIMER: 2539 + case SIL_POLL: 2540 + case SIL_CHLD: 2541 + case SIL_RT: 2542 + case SIL_SYS: 2543 + break; 2544 + } 2545 + } 2546 + 2527 2547 bool get_signal(struct ksignal *ksig) 2528 2548 { 2529 2549 struct sighand_struct *sighand = current->sighand; ··· 2781 2761 spin_unlock_irq(&sighand->siglock); 2782 2762 2783 2763 ksig->sig = signr; 2764 + 2765 + if (!(ksig->ka.sa.sa_flags & SA_EXPOSE_TAGBITS)) 2766 + hide_si_addr_tag_bits(ksig); 2767 + 2784 2768 return ksig->sig > 0; 2785 2769 } 2786 2770