signal: Remove kernel interal si_code magic
struct siginfo is a union and the kernel since 2.4 has been hiding a union
tag in the high 16bits of si_code using the values:
__SI_KILL
__SI_TIMER
__SI_POLL
__SI_FAULT
__SI_CHLD
__SI_RT
__SI_MESGQ
__SI_SYS
While this looks plausible on the surface, in practice this situation has
not worked well.
- Injected positive signals are not copied to user space properly
unless they have these magic high bits set.
- Injected positive signals are not reported properly by signalfd
unless they have these magic high bits set.
- These kernel internal values leaked to userspace via ptrace_peek_siginfo
- It was possible to inject these kernel internal values and cause the
the kernel to misbehave.
- Kernel developers got confused and expected these kernel internal values
in userspace in kernel self tests.
- Kernel developers got confused and set si_code to __SI_FAULT which
is SI_USER in userspace which causes userspace to think an ordinary user
set the signal and that it was not kernel generated.
- The values make it impossible to reorganize the code to transform
siginfo_copy_to_user into a plain copy_to_user. As si_code must
be massaged before being passed to userspace.
So remove these kernel internal si codes and make the kernel code simpler
and more maintainable.
To replace these kernel internal magic si_codes introduce the helper
function siginfo_layout, that takes a signal number and an si_code and
computes which union member of siginfo is being used. Have
siginfo_layout return an enumeration so that gcc will have enough
information to warn if a switch statement does not handle all of union
members.
A couple of architectures have a messed up ABI that defines signal specific
duplications of SI_USER which causes more special cases in siginfo_layout
than I would like. The good news is only problem architectures pay the cost.
Update all of the code that used the previous magic __SI_ values to
use the new SIL_ values and to call siginfo_layout to get those
values. Except for signalfd_copyinfo remove the defaults in their
switch statements so that if they miss cases it will show up at
compile time. The default needs to be kept in the switch statement of
signalfd_copyinfo to preserve the current logic as it is missing cases.
Modify the code that copies siginfo si_code to userspace to just copy
and not truncate it to a short first, as that is no longer necessary.
Fixup the siginfo header files to stop including the __SI_ values in
their constants and for the headers that were missing it to properly update
the number of si_codes for each signal type.
The fixes to copy_siginfo_from_user32 has the interesting property
as before my changes it is code that should never have worked as
the __SI_ values were kernel internal.
The idea of not passing the __SI_ values out to userspace and then
not reinserting them has been tested with criu and criu worked without
changes.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
25 files changed