Peter Collingbourne <pcc@xxxxxxxxxx> writes: > 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@xxxxxxxxxx> > Acked-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> > Link: https://linux-review.googlesource.com/id/I16dd0ed2081f091fce97be0190cb8caa874c26cb > --- > To be applied on top of: > https://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git signal-for-v5.11 I have merged this first patch into signal-for-v5.11 and pushed everything out to linux-next. Eric > include/linux/signal.h | 14 ++++++++++++++ > include/linux/signal_types.h | 2 +- > include/uapi/asm-generic/signal-defs.h | 3 +++ > kernel/signal.c | 24 ++++++++++++++++++++++++ > 4 files changed, 42 insertions(+), 1 deletion(-) > > diff --git a/include/linux/signal.h b/include/linux/signal.h > index b256f9c65661..205526c4003a 100644 > --- a/include/linux/signal.h > +++ b/include/linux/signal.h > @@ -469,4 +469,18 @@ struct seq_file; > extern void render_sigset_t(struct seq_file *, const char *, sigset_t *); > #endif > > +#ifndef arch_untagged_si_addr > +/* > + * Given a fault address and a signal and si_code which correspond to the > + * _sigfault union member, returns the address that must appear in si_addr if > + * the signal handler does not have SA_EXPOSE_TAGBITS enabled in sa_flags. > + */ > +static inline void __user *arch_untagged_si_addr(void __user *addr, > + unsigned long sig, > + unsigned long si_code) > +{ > + return addr; > +} > +#endif > + > #endif /* _LINUX_SIGNAL_H */ > diff --git a/include/linux/signal_types.h b/include/linux/signal_types.h > index a7887ad84d36..68e06c75c5b2 100644 > --- a/include/linux/signal_types.h > +++ b/include/linux/signal_types.h > @@ -78,6 +78,6 @@ struct ksignal { > > #define UAPI_SA_FLAGS \ > (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \ > - SA_NODEFER | SA_RESETHAND | __ARCH_UAPI_SA_FLAGS) > + SA_NODEFER | SA_RESETHAND | SA_EXPOSE_TAGBITS | __ARCH_UAPI_SA_FLAGS) > > #endif /* _LINUX_SIGNAL_TYPES_H */ > diff --git a/include/uapi/asm-generic/signal-defs.h b/include/uapi/asm-generic/signal-defs.h > index c790f67304ba..fe929e7b77ca 100644 > --- a/include/uapi/asm-generic/signal-defs.h > +++ b/include/uapi/asm-generic/signal-defs.h > @@ -20,6 +20,8 @@ > * so this bit allows flag bit support to be detected from userspace while > * allowing an old kernel to be distinguished from a kernel that supports every > * flag bit. > + * SA_EXPOSE_TAGBITS exposes an architecture-defined set of tag bits in > + * siginfo.si_addr. > * > * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single > * Unix names RESETHAND and NODEFER respectively. > @@ -41,6 +43,7 @@ > /* 0x00000100 used on sparc */ > /* 0x00000200 used on sparc */ > #define SA_UNSUPPORTED 0x00000400 > +#define SA_EXPOSE_TAGBITS 0x00000800 > /* 0x00010000 used on mips */ > /* 0x01000000 used on x86 */ > /* 0x02000000 used on x86 */ > diff --git a/kernel/signal.c b/kernel/signal.c > index 8f34819e80de..26018c59821d 100644 > --- a/kernel/signal.c > +++ b/kernel/signal.c > @@ -2524,6 +2524,26 @@ static int ptrace_signal(int signr, kernel_siginfo_t *info) > return signr; > } > > +static void hide_si_addr_tag_bits(struct ksignal *ksig) > +{ > + switch (siginfo_layout(ksig->sig, ksig->info.si_code)) { > + case SIL_FAULT: > + case SIL_FAULT_MCEERR: > + case SIL_FAULT_BNDERR: > + case SIL_FAULT_PKUERR: > + ksig->info.si_addr = arch_untagged_si_addr( > + ksig->info.si_addr, ksig->sig, ksig->info.si_code); > + break; > + case SIL_KILL: > + case SIL_TIMER: > + case SIL_POLL: > + case SIL_CHLD: > + case SIL_RT: > + case SIL_SYS: > + break; > + } > +} > + > bool get_signal(struct ksignal *ksig) > { > struct sighand_struct *sighand = current->sighand; > @@ -2761,6 +2781,10 @@ bool get_signal(struct ksignal *ksig) > spin_unlock_irq(&sighand->siglock); > > ksig->sig = signr; > + > + if (!(ksig->ka.sa.sa_flags & SA_EXPOSE_TAGBITS)) > + hide_si_addr_tag_bits(ksig); > + > return ksig->sig > 0; > }