2018-01-12 00:58:26

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 00/11] siginfo fixes/cleanups esp SI_USER


The following changes are available at:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git siginfo-minor-fixesv2

While answering a question about my earlier introduction to
siginfo_layout I realized that the code introduces a small number
of cases where unitialized memory is copied to userspace as
a result of the fact that SI_USER is sometimes confused with
another si_code.

This modifies all of the places in the kernel that generate a signal
with si_code == SI_USER to fully initialize all of siginfo. Further
this change updates architectures that are using si_code of 0 to
mean something other than SI_USER to use TRAP_FIXME, FPE_FIXME, or
BUS_FIXME to document the problem.

With all these changes take together there is no danger of copying
unitialized values to userspace when SI_USER is mistaken for TRAP_FIXME,
FPE_FIXME or BUS_FIXME.

This series also contains a fix for sh and a fix for openrisc where
they are improperly generating a signal and the fix is obvious.

Eric W. Biederman (11):
signal: Simplify and fix kdb_send_sig
signal/sh: Ensure si_signo is initialized in do_divide_error
signal/openrisc: Fix do_unaligned_access to send the proper signal
signal/parisc: Document a conflict with SI_USER with SIGFPE
signal/metag: Document a conflict with SI_USER with SIGFPE
signal/powerpc: Document conflicts with SI_USER and SIGFPE and SIGTRAP
signal/arm64: Document conflicts with SI_USER and SIGFPE,SIGTRAP,SIGBUS
signal/arm: Document conflicts with SI_USER and SIGFPE
signal: Reduce copy_siginfo to just a memcpy
signal: Introduce clear_siginfo
signal: Ensure generic siginfos the kernel sends have all bits initialized

arch/arm/include/uapi/asm/siginfo.h | 13 ++++
arch/arm/vfp/vfpmodule.c | 2 +-
arch/arm64/include/uapi/asm/siginfo.h | 21 ++++++
arch/arm64/kernel/fpsimd.c | 2 +-
arch/arm64/mm/fault.c | 114 ++++++++++++++++----------------
arch/metag/include/uapi/asm/siginfo.h | 7 ++
arch/metag/kernel/traps.c | 2 +-
arch/openrisc/kernel/traps.c | 10 +--
arch/parisc/include/uapi/asm/siginfo.h | 7 ++
arch/parisc/kernel/traps.c | 2 +-
arch/powerpc/include/uapi/asm/siginfo.h | 15 +++++
arch/powerpc/kernel/traps.c | 10 +--
arch/sh/kernel/traps_32.c | 3 +-
fs/fcntl.c | 1 +
include/linux/signal.h | 13 ++--
ipc/mqueue.c | 1 +
kernel/debug/kdb/kdb_main.c | 10 +--
kernel/debug/kdb/kdb_private.h | 2 +-
kernel/signal.c | 27 +++++---
19 files changed, 167 insertions(+), 95 deletions(-)


2018-01-12 01:01:23

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 01/11] signal: Simplify and fix kdb_send_sig

- Rename from kdb_send_sig_info to kdb_send_sig
As there is no meaningful siginfo sent

- Use SEND_SIG_PRIV instead of generating a siginfo for a kdb
signal. The generated siginfo had a bogus rationale and was
not correct in the face of pid namespaces. SEND_SIG_PRIV
is simpler and actually correct.

- As the code grabs siglock just send the signal with siglock
held instead of dropping siglock and attempting to grab it again.

- Move the sig_valid test into kdb_kill where it can generate
a good error message.

Signed-off-by: Eric W. Biederman <[email protected]>
---
kernel/debug/kdb/kdb_main.c | 10 ++--------
kernel/debug/kdb/kdb_private.h | 2 +-
kernel/signal.c | 14 +++++++-------
3 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index c8146d53ca67..dbb0781a0533 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -2441,7 +2441,6 @@ static int kdb_kill(int argc, const char **argv)
long sig, pid;
char *endp;
struct task_struct *p;
- struct siginfo info;

if (argc != 2)
return KDB_ARGCOUNT;
@@ -2449,7 +2448,7 @@ static int kdb_kill(int argc, const char **argv)
sig = simple_strtol(argv[1], &endp, 0);
if (*endp)
return KDB_BADINT;
- if (sig >= 0) {
+ if ((sig >= 0) || !valid_signal(-sig)) {
kdb_printf("Invalid signal parameter.<-signal>\n");
return 0;
}
@@ -2470,12 +2469,7 @@ static int kdb_kill(int argc, const char **argv)
return 0;
}
p = p->group_leader;
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = SI_USER;
- info.si_pid = pid; /* same capabilities as process being signalled */
- info.si_uid = 0; /* kdb has root authority */
- kdb_send_sig_info(p, &info);
+ kdb_send_sig(p, sig);
return 0;
}

diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
index fc224fbcf954..1e5a502ba4a7 100644
--- a/kernel/debug/kdb/kdb_private.h
+++ b/kernel/debug/kdb/kdb_private.h
@@ -208,7 +208,7 @@ extern unsigned long kdb_task_state(const struct task_struct *p,
extern void kdb_ps_suppressed(void);
extern void kdb_ps1(const struct task_struct *p);
extern void kdb_print_nameval(const char *name, unsigned long val);
-extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info);
+extern void kdb_send_sig(struct task_struct *p, int sig);
extern void kdb_meminfo_proc_show(void);
extern char *kdb_getstr(char *, size_t, const char *);
extern void kdb_gdb_state_pass(char *buf);
diff --git a/kernel/signal.c b/kernel/signal.c
index 9558664bd9ec..c894162ec96c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3684,26 +3684,25 @@ void __init signals_init(void)
#ifdef CONFIG_KGDB_KDB
#include <linux/kdb.h>
/*
- * kdb_send_sig_info - Allows kdb to send signals without exposing
+ * kdb_send_sig - Allows kdb to send signals without exposing
* signal internals. This function checks if the required locks are
* available before calling the main signal code, to avoid kdb
* deadlocks.
*/
-void
-kdb_send_sig_info(struct task_struct *t, struct siginfo *info)
+void kdb_send_sig(struct task_struct *t, int sig)
{
static struct task_struct *kdb_prev_t;
- int sig, new_t;
+ int new_t, ret;
if (!spin_trylock(&t->sighand->siglock)) {
kdb_printf("Can't do kill command now.\n"
"The sigmask lock is held somewhere else in "
"kernel, try again later\n");
return;
}
- spin_unlock(&t->sighand->siglock);
new_t = kdb_prev_t != t;
kdb_prev_t = t;
if (t->state != TASK_RUNNING && new_t) {
+ spin_unlock(&t->sighand->siglock);
kdb_printf("Process is not RUNNING, sending a signal from "
"kdb risks deadlock\n"
"on the run queue locks. "
@@ -3712,8 +3711,9 @@ kdb_send_sig_info(struct task_struct *t, struct siginfo *info)
"the deadlock.\n");
return;
}
- sig = info->si_signo;
- if (send_sig_info(sig, info, t))
+ ret = send_signal(sig, SEND_SIG_PRIV, t, false);
+ spin_unlock(&t->sighand->siglock);
+ if (ret)
kdb_printf("Fail to deliver Signal %d to process %d.\n",
sig, t->pid);
else
--
2.14.1

2018-01-12 01:01:27

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 02/11] signal/sh: Ensure si_signo is initialized in do_divide_error

Set si_signo.

Cc: Yoshinori Sato <[email protected]>
Cc: Rich Felker <[email protected]>
Cc: Paul Mundt <[email protected]>
Cc: [email protected]
Cc: [email protected]
Fixes: 0983b31849bb ("sh: Wire up division and address error exceptions on SH-2A.")
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/sh/kernel/traps_32.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 57cff00cad17..b3770bb26211 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -609,7 +609,8 @@ asmlinkage void do_divide_error(unsigned long r4)
break;
}

- force_sig_info(SIGFPE, &info, current);
+ info.si_signo = SIGFPE;
+ force_sig_info(info.si_signo, &info, current);
}
#endif

--
2.14.1

2018-01-12 01:01:35

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE

Setting si_code to 0 results in a userspace seeing an si_code of 0.
This is the same si_code as SI_USER. Posix and common sense requires
that SI_USER not be a signal specific si_code. As such this use of 0
for the si_code is a pretty horribly broken ABI.

Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
value of __SI_KILL and now sees a value of SIL_KILL with the result
that uid and pid fields are copied and which might copying the si_addr
field by accident but certainly not by design. Making this a very
flakey implementation.

Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
appropriate fields will reliably be copied.

This bug is 13 years old and parsic machines are no longer being built
so I don't know if it possible or worth fixing it. But it is at least
worth documenting this so other architectures don't make the same
mistake.

Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen

Cc: "James E.J. Bottomley" <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: [email protected]
Ref: 313c01d3e3fd ("[PATCH] PA-RISC update for 2.6.0")
Histroy Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/parisc/include/uapi/asm/siginfo.h | 7 +++++++
arch/parisc/kernel/traps.c | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h
index 4a1062e05aaf..be40331f757d 100644
--- a/arch/parisc/include/uapi/asm/siginfo.h
+++ b/arch/parisc/include/uapi/asm/siginfo.h
@@ -8,4 +8,11 @@

#include <asm-generic/siginfo.h>

+/*
+ * SIGFPE si_codes
+ */
+#ifdef __KERNEL__
+#define FPE_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
#endif
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 8453724b8009..c919e6c0a687 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -629,7 +629,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
si.si_signo = SIGFPE;
/* Set to zero, and let the userspace app figure it out from
the insn pointed to by si_addr */
- si.si_code = 0;
+ si.si_code = FPE_FIXME;
si.si_addr = (void __user *) regs->iaoq[0];
force_sig_info(SIGFPE, &si, current);
return;
--
2.14.1

2018-01-12 01:01:43

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE,SIGTRAP,SIGBUS

Setting si_code to 0 results in a userspace seeing an si_code of 0.
This is the same si_code as SI_USER. Posix and common sense requires
that SI_USER not be a signal specific si_code. As such this use of 0
for the si_code is a pretty horribly broken ABI.

Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
value of __SI_KILL and now sees a value of SIL_KILL with the result
that uid and pid fields are copied and which might copying the si_addr
field by accident but certainly not by design. Making this a very
flakey implementation.

Utilizing FPE_FIXME, BUS_FIXME, TRAP_FIXME siginfo_layout will now return
SIL_FAULT and the appropriate fields will be reliably copied.

But folks this is a new and unique kind of bad. This is massively
untested code bad. This is inventing new and unique was to get
siginfo wrong bad. This is don't even think about Posix or what
siginfo means bad. This is lots of eyeballs all missing the fact
that the code does the wrong thing bad. This is getting stuck
and keep making the same mistake bad.

I really hope we can find a non userspace breaking fix for this on a
port as new as arm64.

Possible ABI fixes include:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen

Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Tyler Baicar <[email protected]>
Cc: James Morse <[email protected]>
Cc: Tony Lindgren <[email protected]>
Cc: Nicolas Pitre <[email protected]>
Cc: Olof Johansson <[email protected]>
Cc: Santosh Shilimkar <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: [email protected]
Ref: 53631b54c870 ("arm64: Floating point and SIMD")
Ref: 32015c235603 ("arm64: exception: handle Synchronous External Abort")
Ref: 1d18c47c735e ("arm64: MMU fault handling and page table management")
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arm64/include/uapi/asm/siginfo.h | 21 +++++++
arch/arm64/kernel/fpsimd.c | 2 +-
arch/arm64/mm/fault.c | 114 +++++++++++++++++-----------------
kernel/signal.c | 4 ++
4 files changed, 83 insertions(+), 58 deletions(-)

diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
index 574d12f86039..9b4d91277742 100644
--- a/arch/arm64/include/uapi/asm/siginfo.h
+++ b/arch/arm64/include/uapi/asm/siginfo.h
@@ -21,4 +21,25 @@

#include <asm-generic/siginfo.h>

+/*
+ * SIGFPE si_codes
+ */
+#ifdef __KERNEL__
+#define FPE_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
+/*
+ * SIGBUS si_codes
+ */
+#ifdef __KERNEL__
+#define BUS_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
+/*
+ * SIGTRAP si_codes
+ */
+#ifdef __KERNEL__
+#define TRAP_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
#endif
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index fae81f7964b4..ad0edf31e247 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
{
siginfo_t info;
- unsigned int si_code = 0;
+ unsigned int si_code = FPE_FIXME;

if (esr & FPEXC_IOF)
si_code = FPE_FLTINV;
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 9b7f89df49db..abe200587334 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)

info.si_signo = SIGBUS;
info.si_errno = 0;
- info.si_code = 0;
+ info.si_code = BUS_FIXME;
if (esr & ESR_ELx_FnV)
info.si_addr = NULL;
else
@@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
}

static const struct fault_info fault_info[] = {
- { do_bad, SIGBUS, 0, "ttbr address size fault" },
- { do_bad, SIGBUS, 0, "level 1 address size fault" },
- { do_bad, SIGBUS, 0, "level 2 address size fault" },
- { do_bad, SIGBUS, 0, "level 3 address size fault" },
+ { do_bad, SIGBUS, BUS_FIXME, "ttbr address size fault" },
+ { do_bad, SIGBUS, BUS_FIXME, "level 1 address size fault" },
+ { do_bad, SIGBUS, BUS_FIXME, "level 2 address size fault" },
+ { do_bad, SIGBUS, BUS_FIXME, "level 3 address size fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
- { do_bad, SIGBUS, 0, "unknown 8" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 8" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
- { do_bad, SIGBUS, 0, "unknown 12" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 12" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
- { do_sea, SIGBUS, 0, "synchronous external abort" },
- { do_bad, SIGBUS, 0, "unknown 17" },
- { do_bad, SIGBUS, 0, "unknown 18" },
- { do_bad, SIGBUS, 0, "unknown 19" },
- { do_sea, SIGBUS, 0, "level 0 (translation table walk)" },
- { do_sea, SIGBUS, 0, "level 1 (translation table walk)" },
- { do_sea, SIGBUS, 0, "level 2 (translation table walk)" },
- { do_sea, SIGBUS, 0, "level 3 (translation table walk)" },
- { do_sea, SIGBUS, 0, "synchronous parity or ECC error" }, // Reserved when RAS is implemented
- { do_bad, SIGBUS, 0, "unknown 25" },
- { do_bad, SIGBUS, 0, "unknown 26" },
- { do_bad, SIGBUS, 0, "unknown 27" },
- { do_sea, SIGBUS, 0, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_sea, SIGBUS, 0, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_sea, SIGBUS, 0, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_sea, SIGBUS, 0, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_bad, SIGBUS, 0, "unknown 32" },
+ { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 17" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 18" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 19" },
+ { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" },
+ { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" },
+ { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" },
+ { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },
+ { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implemented
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 25" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 26" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 27" },
+ { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 32" },
{ do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" },
- { do_bad, SIGBUS, 0, "unknown 34" },
- { do_bad, SIGBUS, 0, "unknown 35" },
- { do_bad, SIGBUS, 0, "unknown 36" },
- { do_bad, SIGBUS, 0, "unknown 37" },
- { do_bad, SIGBUS, 0, "unknown 38" },
- { do_bad, SIGBUS, 0, "unknown 39" },
- { do_bad, SIGBUS, 0, "unknown 40" },
- { do_bad, SIGBUS, 0, "unknown 41" },
- { do_bad, SIGBUS, 0, "unknown 42" },
- { do_bad, SIGBUS, 0, "unknown 43" },
- { do_bad, SIGBUS, 0, "unknown 44" },
- { do_bad, SIGBUS, 0, "unknown 45" },
- { do_bad, SIGBUS, 0, "unknown 46" },
- { do_bad, SIGBUS, 0, "unknown 47" },
- { do_bad, SIGBUS, 0, "TLB conflict abort" },
- { do_bad, SIGBUS, 0, "Unsupported atomic hardware update fault" },
- { do_bad, SIGBUS, 0, "unknown 50" },
- { do_bad, SIGBUS, 0, "unknown 51" },
- { do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" },
- { do_bad, SIGBUS, 0, "implementation fault (unsupported exclusive)" },
- { do_bad, SIGBUS, 0, "unknown 54" },
- { do_bad, SIGBUS, 0, "unknown 55" },
- { do_bad, SIGBUS, 0, "unknown 56" },
- { do_bad, SIGBUS, 0, "unknown 57" },
- { do_bad, SIGBUS, 0, "unknown 58" },
- { do_bad, SIGBUS, 0, "unknown 59" },
- { do_bad, SIGBUS, 0, "unknown 60" },
- { do_bad, SIGBUS, 0, "section domain fault" },
- { do_bad, SIGBUS, 0, "page domain fault" },
- { do_bad, SIGBUS, 0, "unknown 63" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 34" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 35" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 36" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 37" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 38" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 39" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 40" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 41" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 42" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 43" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 44" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 45" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 46" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 47" },
+ { do_bad, SIGBUS, BUS_FIXME, "TLB conflict abort" },
+ { do_bad, SIGBUS, BUS_FIXME, "Unsupported atomic hardware update fault" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 50" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 51" },
+ { do_bad, SIGBUS, BUS_FIXME, "implementation fault (lockdown abort)" },
+ { do_bad, SIGBUS, BUS_FIXME, "implementation fault (unsupported exclusive)" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 54" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 55" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 56" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 57" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 58" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 59" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 60" },
+ { do_bad, SIGBUS, BUS_FIXME, "section domain fault" },
+ { do_bad, SIGBUS, BUS_FIXME, "page domain fault" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 63" },
};

int handle_guest_sea(phys_addr_t addr, unsigned int esr)
@@ -739,11 +739,11 @@ static struct fault_info __refdata debug_fault_info[] = {
{ do_bad, SIGTRAP, TRAP_HWBKPT, "hardware breakpoint" },
{ do_bad, SIGTRAP, TRAP_HWBKPT, "hardware single-step" },
{ do_bad, SIGTRAP, TRAP_HWBKPT, "hardware watchpoint" },
- { do_bad, SIGBUS, 0, "unknown 3" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 3" },
{ do_bad, SIGTRAP, TRAP_BRKPT, "aarch32 BKPT" },
- { do_bad, SIGTRAP, 0, "aarch32 vector catch" },
+ { do_bad, SIGTRAP, TRAP_FIXME, "aarch32 vector catch" },
{ early_brk64, SIGTRAP, TRAP_BRKPT, "aarch64 BRK" },
- { do_bad, SIGBUS, 0, "unknown 7" },
+ { do_bad, SIGBUS, BUS_FIXME, "unknown 7" },
};

void __init hook_debug_fault_code(int nr,
diff --git a/kernel/signal.c b/kernel/signal.c
index c894162ec96c..fd182a845490 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2711,6 +2711,10 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
#ifdef FPE_FIXME
if ((sig == SIGFPE) && (si_code == FPE_FIXME))
layout = SIL_FAULT;
+#endif
+#ifdef BUS_FIXME
+ if ((sig == SIGBUS) && (si_code == BUS_FIXME))
+ layout = SIL_FAULT;
#endif
}
return layout;
--
2.14.1

2018-01-12 01:01:53

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 10/11] signal: Introduce clear_siginfo

Unfortunately struct siginfo has holes both in the common part of the
structure, in the union members, and in the lack of padding of the
union members. The result of those wholes is that the C standard does
not guarantee those bits will be initialized. As struct siginfo is
for communication between the kernel and userspace that is a problem.

Add the helper function clear_siginfo that is guaranteed to clear all of
the bits in struct siginfo so when the structure is copied there is no danger
of copying old kernel data and causing a leak of information from kernel
space to userspace.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/linux/signal.h | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/include/linux/signal.h b/include/linux/signal.h
index 8037b503ce91..87abf0c29ed7 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -16,6 +16,11 @@ static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from)
memcpy(to, from, sizeof(*to));
}

+static inline void clear_siginfo(struct siginfo *info)
+{
+ memset(info, 0, sizeof(*info));
+}
+
int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);

enum siginfo_layout {
--
2.14.1

2018-01-12 01:01:40

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 06/11] signal/powerpc: Document conflicts with SI_USER and SIGFPE and SIGTRAP

Setting si_code to 0 results in a userspace seeing an si_code of 0.
This is the same si_code as SI_USER. Posix and common sense requires
that SI_USER not be a signal specific si_code. As such this use of 0
for the si_code is a pretty horribly broken ABI.

Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
value of __SI_KILL and now sees a value of SIL_KILL with the result
that uid and pid fields are copied and which might copying the si_addr
field by accident but certainly not by design. Making this a very
flakey implementation.

Utilizing FPE_FIXME and TRAP_FIXME, siginfo_layout() will now return
SIL_FAULT and the appropriate fields will be reliably copied.

Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen
Cc: Paul Mackerras <[email protected]>
Cc: Kumar Gala <[email protected]>
Cc: Michael Ellerman <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: [email protected]
Ref: 9bad068c24d7 ("[PATCH] ppc32: support for e500 and 85xx")
Ref: 0ed70f6105ef ("PPC32: Provide proper siginfo information on various exceptions.")
History Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/powerpc/include/uapi/asm/siginfo.h | 15 +++++++++++++++
arch/powerpc/kernel/traps.c | 10 +++++-----
2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/uapi/asm/siginfo.h b/arch/powerpc/include/uapi/asm/siginfo.h
index 1a691141e49f..444ca6c9989a 100644
--- a/arch/powerpc/include/uapi/asm/siginfo.h
+++ b/arch/powerpc/include/uapi/asm/siginfo.h
@@ -18,4 +18,19 @@
#undef NSIGTRAP
#define NSIGTRAP 4

+/*
+ * SIGFPE si_codes
+ */
+#ifdef __KERNEL__
+#define FPE_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
+/*
+ * SIGTRAP si_codes
+ */
+#ifdef __KERNEL__
+#define TRAP_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
+
#endif /* _ASM_POWERPC_SIGINFO_H */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index f3eb61be0d30..f2e6e1838952 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -917,7 +917,7 @@ void unknown_exception(struct pt_regs *regs)
printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
regs->nip, regs->msr, regs->trap);

- _exception(SIGTRAP, regs, 0, 0);
+ _exception(SIGTRAP, regs, TRAP_FIXME, 0);

exception_exit(prev_state);
}
@@ -939,7 +939,7 @@ void instruction_breakpoint_exception(struct pt_regs *regs)

void RunModeException(struct pt_regs *regs)
{
- _exception(SIGTRAP, regs, 0, 0);
+ _exception(SIGTRAP, regs, TRAP_FIXME, 0);
}

void single_step_exception(struct pt_regs *regs)
@@ -978,7 +978,7 @@ static void emulate_single_step(struct pt_regs *regs)

static inline int __parse_fpscr(unsigned long fpscr)
{
- int ret = 0;
+ int ret = FPE_FIXME;

/* Invalid operation */
if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
@@ -1929,7 +1929,7 @@ void SPEFloatingPointException(struct pt_regs *regs)
extern int do_spe_mathemu(struct pt_regs *regs);
unsigned long spefscr;
int fpexc_mode;
- int code = 0;
+ int code = FPE_FIXME;
int err;

flush_spe_to_thread(current);
@@ -1998,7 +1998,7 @@ void SPEFloatingPointRoundException(struct pt_regs *regs)
printk(KERN_ERR "unrecognized spe instruction "
"in %s at %lx\n", current->comm, regs->nip);
} else {
- _exception(SIGFPE, regs, 0, regs->nip);
+ _exception(SIGFPE, regs, FPE_FIXME, regs->nip);
return;
}
}
--
2.14.1

2018-01-12 01:02:31

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 09/11] signal: Reduce copy_siginfo to just a memcpy

The savings for copying just part of struct siginfo appears to be in the
noise on modern machines. So remove this ``optimization'' and simplify the code.

At the same time mark the second parameter as constant so there is no confusion
as to which direction the copy will go.

This ensures that a fully initialized siginfo that is sent ends up as
a fully initialized siginfo on the signal queue. This full initialization
ensures even confused code won't copy unitialized data to userspace, and
it prepares for turning copy_siginfo_to_user into a simple copy_to_user.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/linux/signal.h | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/include/linux/signal.h b/include/linux/signal.h
index 042968dd98f0..8037b503ce91 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -11,13 +11,9 @@ struct task_struct;
/* for sysctl */
extern int print_fatal_signals;

-static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
+static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from)
{
- if (from->si_code < 0)
- memcpy(to, from, sizeof(*to));
- else
- /* _sigchld is currently the largest know union member */
- memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
+ memcpy(to, from, sizeof(*to));
}

int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);
--
2.14.1

2018-01-12 01:02:49

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE

Setting si_code to 0 results in a userspace seeing an si_code of 0.
This is the same si_code as SI_USER. Posix and common sense requires
that SI_USER not be a signal specific si_code. As such this use of 0
for the si_code is a pretty horribly broken ABI.

Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
value of __SI_KILL and now sees a value of SIL_KILL with the result
that uid and pid fields are copied and which might copying the si_addr
field by accident but certainly not by design. Making this a very
flakey implementation.

Utilizing FPE_FIXME, siginfo_layout will now return SIL_FAULT and the
appropriate fields will be reliably copied.

Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen

Cc: Russell King <[email protected]>
Cc: [email protected]
Ref: 451436b7bbb2 ("[ARM] Add support code for ARM hardware vector floating point")
History Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arm/include/uapi/asm/siginfo.h | 13 +++++++++++++
arch/arm/vfp/vfpmodule.c | 2 +-
2 files changed, 14 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/include/uapi/asm/siginfo.h

diff --git a/arch/arm/include/uapi/asm/siginfo.h b/arch/arm/include/uapi/asm/siginfo.h
new file mode 100644
index 000000000000..d0513880be21
--- /dev/null
+++ b/arch/arm/include/uapi/asm/siginfo.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_SIGINFO_H
+#define __ASM_SIGINFO_H
+
+#include <asm-generic/siginfo.h>
+
+/*
+ * SIGFPE si_codes
+ */
+#ifdef __KERNEL__
+#define FPE_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index a71a48e71fff..03c6a3c72f9c 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -257,7 +257,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_

if (exceptions == VFP_EXCEPTION_ERROR) {
vfp_panic("unhandled bounce", inst);
- vfp_raise_sigfpe(0, regs);
+ vfp_raise_sigfpe(FPE_FIXME, regs);
return;
}

--
2.14.1

2018-01-12 01:01:32

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 03/11] signal/openrisc: Fix do_unaligned_access to send the proper signal

While reviewing the signal sending on openrisc the do_unaligned_access
function stood out because it is obviously wrong. A comment about an
si_code set above when actually si_code is never set. Leading to a
random si_code being sent to userspace in the event of an unaligned
access.

Looking further SIGBUS BUS_ADRALN is the proper pair of signal and
si_code to send for an unaligned access. That is what other
architectures do and what is required by posix.

Given that do_unaligned_access is broken in a way that no one can be
relying on it on openrisc fix the code to just do the right thing.

Cc: [email protected]
Fixes: 769a8a96229e ("OpenRISC: Traps")
Cc: Jonas Bonn <[email protected]>
Cc: Stefan Kristiansson <[email protected]>
Cc: Stafford Horne <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: [email protected]
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/openrisc/kernel/traps.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
index 4085d72fa5ae..9e38dc66c9e4 100644
--- a/arch/openrisc/kernel/traps.c
+++ b/arch/openrisc/kernel/traps.c
@@ -266,12 +266,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
siginfo_t info;

if (user_mode(regs)) {
- /* Send a SIGSEGV */
- info.si_signo = SIGSEGV;
+ /* Send a SIGBUS */
+ info.si_signo = SIGBUS;
info.si_errno = 0;
- /* info.si_code has been set above */
- info.si_addr = (void *)address;
- force_sig_info(SIGSEGV, &info, current);
+ info.si_code = BUS_ADRALN;
+ info.si_addr = (void __user *)address;
+ force_sig_info(SIGBUS, &info, current);
} else {
printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
show_registers(regs);
--
2.14.1

2018-01-12 01:03:52

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 05/11] signal/metag: Document a conflict with SI_USER with SIGFPE

Setting si_code to 0 results in a userspace seeing an si_code of 0.
This is the same si_code as SI_USER. Posix and common sense requires
that SI_USER not be a signal specific si_code. As such this use of 0
for the si_code is a pretty horribly broken ABI.

Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
value of __SI_KILL and now sees a value of SIL_KILL with the result
hat uid and pid fields are copied and which might copying the si_addr
field by accident but certainly not by design. Making this a very
flakey implementation.

Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
appropriate fields will reliably be copied.

Possible ABI fixes includee:
- Send the signal without siginfo
- Don't generate a signal
- Possibly assign and use an appropriate si_code
- Don't handle cases which can't happen

Cc: James Hogan <[email protected]>
Cc: [email protected]
Ref: ac919f0883e5 ("metag: Traps")
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/metag/include/uapi/asm/siginfo.h | 7 +++++++
arch/metag/kernel/traps.c | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/metag/include/uapi/asm/siginfo.h b/arch/metag/include/uapi/asm/siginfo.h
index b54ef7186ca3..9a3f6cde9487 100644
--- a/arch/metag/include/uapi/asm/siginfo.h
+++ b/arch/metag/include/uapi/asm/siginfo.h
@@ -6,4 +6,11 @@

#include <asm-generic/siginfo.h>

+/*
+ * SIGFPE si_codes
+ */
+#ifdef __KERNEL__
+#define FPE_FIXME 0 /* Broken dup of SI_USER */
+#endif /* __KERNEL__ */
+
#endif
diff --git a/arch/metag/kernel/traps.c b/arch/metag/kernel/traps.c
index 444851e510d5..3b62b1b0c0b5 100644
--- a/arch/metag/kernel/traps.c
+++ b/arch/metag/kernel/traps.c
@@ -735,7 +735,7 @@ TBIRES fpe_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
else if (error_state & TXSTAT_FPE_INEXACT_BIT)
info.si_code = FPE_FLTRES;
else
- info.si_code = 0;
+ info.si_code = FPE_FIXME;
info.si_errno = 0;
info.si_addr = (__force void __user *)regs->ctx.CurrPC;
force_sig_info(SIGFPE, &info, current);
--
2.14.1

2018-01-12 01:06:20

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 11/11] signal: Ensure generic siginfos the kernel sends have all bits initialized

Call clear_siginfo to ensure stack allocated siginfos are fully
initialized before being passed to the signal sending functions.

This ensures that if there is the kind of confusion documented by
TRAP_FIXME, FPE_FIXME, or BUS_FIXME the kernel won't send unitialized
data to userspace when the kernel generates a signal with SI_USER but
the copy to userspace assumes it is a different kind of signal, and
different fields are initialized.

This also prepares the way for turning copy_siginfo_to_user
into a copy_to_user, by removing the need in many cases to perform
a field by field copy simply to skip the uninitialized fields.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
fs/fcntl.c | 1 +
ipc/mqueue.c | 1 +
kernel/signal.c | 9 ++++++++-
3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index 0522e283a4f4..c17369659f4a 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -737,6 +737,7 @@ static void send_sigio_to_task(struct task_struct *p,
delivered even if we can't queue. Failure to
queue in this case _should_ be reported; we fall
back to SIGIO in that case. --sct */
+ clear_siginfo(&si);
si.si_signo = signum;
si.si_errno = 0;
si.si_code = reason;
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 9649ecd8a73a..17bc8b874d92 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -639,6 +639,7 @@ static void __do_notify(struct mqueue_inode_info *info)
case SIGEV_SIGNAL:
/* sends signal */

+ clear_siginfo(&sig_i);
sig_i.si_signo = info->notify.sigev_signo;
sig_i.si_errno = 0;
sig_i.si_code = SI_MESGQ;
diff --git a/kernel/signal.c b/kernel/signal.c
index fd182a845490..241d54958bbb 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -549,6 +549,7 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info,
* a fast-pathed signal or we must have been
* out of queue space. So zero out the info.
*/
+ clear_siginfo(info);
info->si_signo = sig;
info->si_errno = 0;
info->si_code = SI_USER;
@@ -1043,6 +1044,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
list_add_tail(&q->list, &pending->list);
switch ((unsigned long) info) {
case (unsigned long) SEND_SIG_NOINFO:
+ clear_siginfo(&q->info);
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_USER;
@@ -1051,6 +1053,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
break;
case (unsigned long) SEND_SIG_PRIV:
+ clear_siginfo(&q->info);
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_KERNEL;
@@ -1623,6 +1626,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
sig = SIGCHLD;
}

+ clear_siginfo(&info);
info.si_signo = sig;
info.si_errno = 0;
/*
@@ -1717,6 +1721,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
parent = tsk->real_parent;
}

+ clear_siginfo(&info);
info.si_signo = SIGCHLD;
info.si_errno = 0;
/*
@@ -1929,7 +1934,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
{
siginfo_t info;

- memset(&info, 0, sizeof info);
+ clear_siginfo(&info);
info.si_signo = signr;
info.si_code = exit_code;
info.si_pid = task_pid_vnr(current);
@@ -2136,6 +2141,7 @@ static int ptrace_signal(int signr, siginfo_t *info)
* have updated *info via PTRACE_SETSIGINFO.
*/
if (signr != info->si_signo) {
+ clear_siginfo(info);
info->si_signo = signr;
info->si_errno = 0;
info->si_code = SI_USER;
@@ -2941,6 +2947,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
{
struct siginfo info;

+ clear_siginfo(&info);
info.si_signo = sig;
info.si_errno = 0;
info.si_code = SI_USER;
--
2.14.1

2018-01-12 13:25:29

by Stafford Horne

[permalink] [raw]
Subject: Re: [PATCH 03/11] signal/openrisc: Fix do_unaligned_access to send the proper signal

On Thu, Jan 11, 2018 at 06:59:32PM -0600, Eric W. Biederman wrote:
> While reviewing the signal sending on openrisc the do_unaligned_access
> function stood out because it is obviously wrong. A comment about an
> si_code set above when actually si_code is never set. Leading to a
> random si_code being sent to userspace in the event of an unaligned
> access.
>
> Looking further SIGBUS BUS_ADRALN is the proper pair of signal and
> si_code to send for an unaligned access. That is what other
> architectures do and what is required by posix.
>
> Given that do_unaligned_access is broken in a way that no one can be
> relying on it on openrisc fix the code to just do the right thing.

Thanks, this looks good to me.

Acked-by: Stafford Horne <[email protected]>

I see you have a series of related issues, so I guess you want to get them
merged together. Let me know if I should put this patch onto my queue
seperately.

Trivia: this looks to have been copied from the mm page fault handling code,
hence the strange comment.

$ grep -r "info.si_code has been set above" arch/
arch/cris/mm/fault.c: /* info.si_code has been set above */
arch/m32r/mm/fault.c: /* info.si_code has been set above */
arch/mn10300/mm/fault.c: /* info.si_code has been set above */
arch/openrisc/mm/fault.c: /* info.si_code has been set above */
arch/openrisc/kernel/traps.c: /* info.si_code has been set above */
arch/arc/mm/fault.c: /* info.si_code has been set above */
arch/xtensa/mm/fault.c: /* info.si_code has been set above */
arch/mips/mm/fault.c: /* info.si_code has been set above */
arch/score/mm/fault.c: /* info.si_code has been set above */
arch/frv/mm/fault.c: /* info.si_code has been set above */

-Stafford

> Cc: [email protected]
> Fixes: 769a8a96229e ("OpenRISC: Traps")
> Cc: Jonas Bonn <[email protected]>
> Cc: Stefan Kristiansson <[email protected]>
> Cc: Stafford Horne <[email protected]>
> Cc: Arnd Bergmann <[email protected]>
> Cc: [email protected]
> Signed-off-by: "Eric W. Biederman" <[email protected]>
> ---
> arch/openrisc/kernel/traps.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
> index 4085d72fa5ae..9e38dc66c9e4 100644
> --- a/arch/openrisc/kernel/traps.c
> +++ b/arch/openrisc/kernel/traps.c
> @@ -266,12 +266,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
> siginfo_t info;
>
> if (user_mode(regs)) {
> - /* Send a SIGSEGV */
> - info.si_signo = SIGSEGV;
> + /* Send a SIGBUS */
> + info.si_signo = SIGBUS;
> info.si_errno = 0;
> - /* info.si_code has been set above */
> - info.si_addr = (void *)address;
> - force_sig_info(SIGSEGV, &info, current);
> + info.si_code = BUS_ADRALN;
> + info.si_addr = (void __user *)address;
> + force_sig_info(SIGBUS, &info, current);
> } else {
> printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
> show_registers(regs);
> --
> 2.14.1
>

2018-01-12 17:38:33

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 03/11] signal/openrisc: Fix do_unaligned_access to send the proper signal

Stafford Horne <[email protected]> writes:

> On Thu, Jan 11, 2018 at 06:59:32PM -0600, Eric W. Biederman wrote:
>> While reviewing the signal sending on openrisc the do_unaligned_access
>> function stood out because it is obviously wrong. A comment about an
>> si_code set above when actually si_code is never set. Leading to a
>> random si_code being sent to userspace in the event of an unaligned
>> access.
>>
>> Looking further SIGBUS BUS_ADRALN is the proper pair of signal and
>> si_code to send for an unaligned access. That is what other
>> architectures do and what is required by posix.
>>
>> Given that do_unaligned_access is broken in a way that no one can be
>> relying on it on openrisc fix the code to just do the right thing.
>
> Thanks, this looks good to me.
>
> Acked-by: Stafford Horne <[email protected]>
>
> I see you have a series of related issues, so I guess you want to get them
> merged together. Let me know if I should put this patch onto my queue
> seperately.

Yes, I have a follow on patch that restructures the code that fills out
siginfo, and makes the it a little less error prone. I am hoping to
merge all of it in the next merge window. *Fingers crossed*

And having it all in one tree will facilitate that.

> Trivia: this looks to have been copied from the mm page fault handling code,
> hence the strange comment.
>
> $ grep -r "info.si_code has been set above" arch/
> arch/cris/mm/fault.c: /* info.si_code has been set above */
> arch/m32r/mm/fault.c: /* info.si_code has been set above */
> arch/mn10300/mm/fault.c: /* info.si_code has been set above */
> arch/openrisc/mm/fault.c: /* info.si_code has been set above */
> arch/openrisc/kernel/traps.c: /* info.si_code has been set above */
> arch/arc/mm/fault.c: /* info.si_code has been set above */
> arch/xtensa/mm/fault.c: /* info.si_code has been set above */
> arch/mips/mm/fault.c: /* info.si_code has been set above */
> arch/score/mm/fault.c: /* info.si_code has been set above */
> arch/frv/mm/fault.c: /* info.si_code has been set above */
>

It looks like it. When I look at those I can actually find the
si_code being set higher up in the code. It looks like the si_code
value was missed when this work was done.

Eric

2018-01-12 20:30:45

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 0/2] siginfo fixes


These are two additional siginfo fixes I overlooked yesterday.
Thankfully the confusion was not arch specific, and did not set an ABI
to userspace that I had to worry about breaking, so I could fix these
two issues properly.

Eric W. Biederman (2):
mn10300/misalignment: Use SIGSEGV SEGV_MAPERR to report a failed user copy
x86/mm/pkeys: Fix fill_sig_info_pkey

arch/mn10300/mm/misalignment.c | 2 +-
arch/x86/mm/fault.c | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)

2018-01-12 20:32:54

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 1/2] mn10300/misalignment: Use SIGSEGV SEGV_MAPERR to report a failed user copy

Setting si_code to 0 is the same a setting si_code to SI_USER which is definitely
not correct. With si_code set to SI_USER si_pid and si_uid will be copied to
userspace instead of si_addr. Which is very wrong.

So fix this by using a sensible si_code (SEGV_MAPERR) for this failure.

Cc: [email protected]
Fixes: b920de1b77b7 ("mn10300: add the MN10300/AM33 architecture to the kernel")
Cc: David Howells <[email protected]>
Cc: Masakazu Urade <[email protected]>
Cc: Koichi Yasutake <[email protected]>
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/mn10300/mm/misalignment.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
index b39a388825ae..8ace89617c1c 100644
--- a/arch/mn10300/mm/misalignment.c
+++ b/arch/mn10300/mm/misalignment.c
@@ -437,7 +437,7 @@ asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)

info.si_signo = SIGSEGV;
info.si_errno = 0;
- info.si_code = 0;
+ info.si_code = SEGV_MAPERR;
info.si_addr = (void *) regs->pc;
force_sig_info(SIGSEGV, &info, current);
return;
--
2.14.1

2018-01-12 20:32:58

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 2/2] x86/mm/pkeys: Fix fill_sig_info_pkey

SEGV_PKUERR is a signal specific si_code which happens to have the
same numeric value as several others: BUS_MCEERR_AR, ILL_ILLTRP,
FPE_FLTOVF, TRAP_HWBKPT, CLD_TRAPPED, POLL_ERR, SEGV_THREAD_ID,
as such it is not safe to just test the si_code the signal number
must also be tested to prevent a false positive in fill_sig_info_pkey.

I found this error by inspection, and BUS_MCEERR_AR appears to
be a real candidate for confusion. So pass in si_signo and fix it.

Cc: Dave Hansen <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Fixes: 019132ff3daf ("x86/mm/pkeys: Fill in pkey field in siginfo")
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/x86/mm/fault.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 06fe3d51d385..b3e40773dce0 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -172,14 +172,15 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
* 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
* faulted on a pte with its pkey=4.
*/
-static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey)
+static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info,
+ u32 *pkey)
{
/* This is effectively an #ifdef */
if (!boot_cpu_has(X86_FEATURE_OSPKE))
return;

/* Fault not from Protection Keys: nothing to do */
- if (si_code != SEGV_PKUERR)
+ if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV))
return;
/*
* force_sig_info_fault() is called from a number of
@@ -218,7 +219,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address,
lsb = PAGE_SHIFT;
info.si_addr_lsb = lsb;

- fill_sig_info_pkey(si_code, &info, pkey);
+ fill_sig_info_pkey(si_signo, si_code, &info, pkey);

force_sig_info(si_signo, &info, tsk);
}
--
2.14.1

2018-01-12 22:30:24

by Helge Deller

[permalink] [raw]
Subject: Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE

* Eric W. Biederman <[email protected]>:
> Setting si_code to 0 results in a userspace seeing an si_code of 0.
> This is the same si_code as SI_USER. Posix and common sense requires
> that SI_USER not be a signal specific si_code. As such this use of 0
> for the si_code is a pretty horribly broken ABI.
>
> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
> value of __SI_KILL and now sees a value of SIL_KILL with the result
> that uid and pid fields are copied and which might copying the si_addr
> field by accident but certainly not by design. Making this a very
> flakey implementation.
>
> Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
> appropriate fields will reliably be copied.
>
> This bug is 13 years old and parsic machines are no longer being built
> so I don't know if it possible or worth fixing it. But it is at least
> worth documenting this so other architectures don't make the same
> mistake.


I think we should fix it, even if we now break the ABI.

It's about a "conditional trap" which needs to be handled by userspace.
I doubt there is any Linux code out which is utilizing this
parisc-specific trap.

I'd suggest to add a new FPE trap si_code (e.g. FPE_CONDTRAP).
While at it, maybe we should include the already existing FPE_MDAOVF
from the frv architecture, so that arch/frv/include/uapi/asm/siginfo.h
can go completely.

Suggested patch is below.

I'm willing to test the patch below on the parisc architecture for a few
weeks. And it will break arch/x86/kernel/signal_compat.c which needs
looking at then too.

Thoughts?

Helge



[PATCH] parisc: Add FPE_CONDTRAP for conditional trap handling

Posix and common sense requires that SI_USER not be a signal specific
si_code. Thus add a new FPE_CONDTRAP si_code for conditional traps.

Signed-off-by: Helge Deller <[email protected]>

diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 8453724b8009..13702f0f5ba1 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -627,9 +627,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
on condition */
if(user_mode(regs)){
si.si_signo = SIGFPE;
- /* Set to zero, and let the userspace app figure it out from
- the insn pointed to by si_addr */
- si.si_code = 0;
+ /* Let userspace app figure out from the insn pointed
+ * to by si_addr */
+ si.si_code = FPE_CONDTRAP;
si.si_addr = (void __user *) regs->iaoq[0];
force_sig_info(SIGFPE, &si, current);
return;
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index e447283b8f52..2b759fe42142 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -193,7 +193,9 @@ typedef struct siginfo {
#define FPE_FLTRES 6 /* floating point inexact result */
#define FPE_FLTINV 7 /* floating point invalid operation */
#define FPE_FLTSUB 8 /* subscript out of range */
-#define NSIGFPE 8
+#define FPE_MDAOVF 9 /* media overflow */
+#define FPE_CONDTRAP 10 /* trap on condition */
+#define NSIGFPE 10

/*
* SIGSEGV si_codes

2018-01-13 21:07:07

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE

Helge Deller <[email protected]> writes:

> * Eric W. Biederman <[email protected]>:
>> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>> This is the same si_code as SI_USER. Posix and common sense requires
>> that SI_USER not be a signal specific si_code. As such this use of 0
>> for the si_code is a pretty horribly broken ABI.
>>
>> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>> value of __SI_KILL and now sees a value of SIL_KILL with the result
>> that uid and pid fields are copied and which might copying the si_addr
>> field by accident but certainly not by design. Making this a very
>> flakey implementation.
>>
>> Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
>> appropriate fields will reliably be copied.
>>
>> This bug is 13 years old and parsic machines are no longer being built
>> so I don't know if it possible or worth fixing it. But it is at least
>> worth documenting this so other architectures don't make the same
>> mistake.
>
>
> I think we should fix it, even if we now break the ABI.
>
> It's about a "conditional trap" which needs to be handled by userspace.
> I doubt there is any Linux code out which is utilizing this
> parisc-specific trap.
>
> I'd suggest to add a new FPE trap si_code (e.g. FPE_CONDTRAP).
> While at it, maybe we should include the already existing FPE_MDAOVF
> from the frv architecture, so that arch/frv/include/uapi/asm/siginfo.h
> can go completely.
>
> Suggested patch is below.
>
> I'm willing to test the patch below on the parisc architecture for a few
> weeks. And it will break arch/x86/kernel/signal_compat.c which needs
> looking at then too.
>
> Thoughts?

I like it.

We have the option of bringing either the ia64 or the frv si_codes
into the generic fold. Is there any reason you choose frv?
Last I looked ia64 tended in many aspects to be well thought out,
and thus worth a careful look.

Given that a couple of weeks likely puts on the other side of the merge
window I would like to start with my patch so I can close the potential
copying of unitialized memory to userspace. Then we can build yours on
top.

Although I am more than happy to add new si_codes now.

What I am in the final stages of testing and reviewing internally is the
change to merge all of struct siginfo, struct compat_siginfo,
copy_siginfo_from_user32 and copy_siginfo_to_user32 together.

I need another couple hours and I will be ready to post that.

For long term maintenance the more we can merge together the better,
as clearly some of these bugs have persisted far too long. And getting
collapsing the arch specific si_codes into just a set of si_codes
looks like one more good step in that direction.

Eric


> Helge
>
>
>
> [PATCH] parisc: Add FPE_CONDTRAP for conditional trap handling
>
> Posix and common sense requires that SI_USER not be a signal specific
> si_code. Thus add a new FPE_CONDTRAP si_code for conditional traps.
>
> Signed-off-by: Helge Deller <[email protected]>
>
> diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
> index 8453724b8009..13702f0f5ba1 100644
> --- a/arch/parisc/kernel/traps.c
> +++ b/arch/parisc/kernel/traps.c
> @@ -627,9 +627,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
> on condition */
> if(user_mode(regs)){
> si.si_signo = SIGFPE;
> - /* Set to zero, and let the userspace app figure it out from
> - the insn pointed to by si_addr */
> - si.si_code = 0;
> + /* Let userspace app figure out from the insn pointed
> + * to by si_addr */
> + si.si_code = FPE_CONDTRAP;
> si.si_addr = (void __user *) regs->iaoq[0];
> force_sig_info(SIGFPE, &si, current);
> return;
> diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
> index e447283b8f52..2b759fe42142 100644
> --- a/include/uapi/asm-generic/siginfo.h
> +++ b/include/uapi/asm-generic/siginfo.h
> @@ -193,7 +193,9 @@ typedef struct siginfo {
> #define FPE_FLTRES 6 /* floating point inexact result */
> #define FPE_FLTINV 7 /* floating point invalid operation */
> #define FPE_FLTSUB 8 /* subscript out of range */
> -#define NSIGFPE 8
> +#define FPE_MDAOVF 9 /* media overflow */
> +#define FPE_CONDTRAP 10 /* trap on condition */
> +#define NSIGFPE 10
>
> /*
> * SIGSEGV si_codes

2018-01-14 01:47:22

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE

[email protected] (Eric W. Biederman) writes:

> Helge Deller <[email protected]> writes:
>
>> * Eric W. Biederman <[email protected]>:
>>> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>>> This is the same si_code as SI_USER. Posix and common sense requires
>>> that SI_USER not be a signal specific si_code. As such this use of 0
>>> for the si_code is a pretty horribly broken ABI.
>>>
>>> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>>> value of __SI_KILL and now sees a value of SIL_KILL with the result
>>> that uid and pid fields are copied and which might copying the si_addr
>>> field by accident but certainly not by design. Making this a very
>>> flakey implementation.
>>>
>>> Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
>>> appropriate fields will reliably be copied.
>>>
>>> This bug is 13 years old and parsic machines are no longer being built
>>> so I don't know if it possible or worth fixing it. But it is at least
>>> worth documenting this so other architectures don't make the same
>>> mistake.
>>
>>
>> I think we should fix it, even if we now break the ABI.
>>
>> It's about a "conditional trap" which needs to be handled by userspace.
>> I doubt there is any Linux code out which is utilizing this
>> parisc-specific trap.
>>
>> I'd suggest to add a new FPE trap si_code (e.g. FPE_CONDTRAP).
>> While at it, maybe we should include the already existing FPE_MDAOVF
>> from the frv architecture, so that arch/frv/include/uapi/asm/siginfo.h
>> can go completely.
>>
>> Suggested patch is below.
>>
>> I'm willing to test the patch below on the parisc architecture for a few
>> weeks. And it will break arch/x86/kernel/signal_compat.c which needs
>> looking at then too.
>>
>> Thoughts?
>
> I like it.

Your comments about the si_codes caused me to look into how they differ
across the architectures and realize they also all need to be merged
into uapi/asm-generic/siginfo.h for sanity sake. In doing so I found
a couple of minor issues with my other unifications.

Rebased onto my tree your patch looks like the below. If it does not
cause any regressions it looks like a perfect fix. The noticable change
is that the first FPE si_code available across all architectures is 14
so I have used 14 instead of 10 for FPE_CONDTRAP.

Eric

From: Helge Deller <[email protected]>
Date: Sat, 13 Jan 2018 19:32:43 -0600
Subject: [PATCH] signal/parisc: Add FPE_CONDTRAP for conditional trap handling

Posix and common sense requires that SI_USER not be a signal specific
si_code. Thus add a new FPE_CONDTRAP si_code for conditional traps.

-- EWB rebased onto my tree.

Signed-off-by: Helge Deller <[email protected]>
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/parisc/include/uapi/asm/siginfo.h | 7 -------
arch/parisc/kernel/traps.c | 7 ++++---
include/uapi/asm-generic/siginfo.h | 3 ++-
3 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h
index be40331f757d..4a1062e05aaf 100644
--- a/arch/parisc/include/uapi/asm/siginfo.h
+++ b/arch/parisc/include/uapi/asm/siginfo.h
@@ -8,11 +8,4 @@

#include <asm-generic/siginfo.h>

-/*
- * SIGFPE si_codes
- */
-#ifdef __KERNEL__
-#define FPE_FIXME 0 /* Broken dup of SI_USER */
-#endif /* __KERNEL__ */
-
#endif
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index c919e6c0a687..68e671a11987 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -627,9 +627,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
on condition */
if(user_mode(regs)){
si.si_signo = SIGFPE;
- /* Set to zero, and let the userspace app figure it out from
- the insn pointed to by si_addr */
- si.si_code = FPE_FIXME;
+ /* Let userspace app figure it out from the insn pointed
+ * to by si_addr.
+ */
+ si.si_code = FPE_CONDTRAP;
si.si_addr = (void __user *) regs->iaoq[0];
force_sig_info(SIGFPE, &si, current);
return;
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 254afc31e3be..ab4fad1a0cf0 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -229,7 +229,8 @@ typedef struct siginfo {
# define __FPE_INVASC 12 /* invalid ASCII digit */
# define __FPE_INVDEC 13 /* invalid decimal digit */
#endif
-#define NSIGFPE 13
+#define FPE_CONDTRAP 14 /* trap on condition */
+#define NSIGFPE 14

/*
* SIGSEGV si_codes
--
2.14.1


Subject: [tip:x86/urgent] x86/mm/pkeys: Fix fill_sig_info_pkey

Commit-ID: beacd6f7ed5e2915959442245b3b2480c2e37490
Gitweb: https://git.kernel.org/tip/beacd6f7ed5e2915959442245b3b2480c2e37490
Author: Eric W. Biederman <[email protected]>
AuthorDate: Fri, 12 Jan 2018 14:31:35 -0600
Committer: Thomas Gleixner <[email protected]>
CommitDate: Sun, 14 Jan 2018 12:14:51 +0100

x86/mm/pkeys: Fix fill_sig_info_pkey

SEGV_PKUERR is a signal specific si_code which happens to have the same
numeric value as several others: BUS_MCEERR_AR, ILL_ILLTRP, FPE_FLTOVF,
TRAP_HWBKPT, CLD_TRAPPED, POLL_ERR, SEGV_THREAD_ID, as such it is not safe
to just test the si_code the signal number must also be tested to prevent a
false positive in fill_sig_info_pkey.

This error was by inspection, and BUS_MCEERR_AR appears to be a real
candidate for confusion. So pass in si_signo and check for SIG_SEGV to
verify that it is actually a SEGV_PKUERR

Fixes: 019132ff3daf ("x86/mm/pkeys: Fill in pkey field in siginfo")
Signed-off-by: "Eric W. Biederman" <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Cc: [email protected]
Cc: Dave Hansen <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: Al Viro <[email protected]>
cc: [email protected]
Link: https://lkml.kernel.org/r/[email protected]

---
arch/x86/mm/fault.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 06fe3d5..b3e4077 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -172,14 +172,15 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
* 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
* faulted on a pte with its pkey=4.
*/
-static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey)
+static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info,
+ u32 *pkey)
{
/* This is effectively an #ifdef */
if (!boot_cpu_has(X86_FEATURE_OSPKE))
return;

/* Fault not from Protection Keys: nothing to do */
- if (si_code != SEGV_PKUERR)
+ if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV))
return;
/*
* force_sig_info_fault() is called from a number of
@@ -218,7 +219,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address,
lsb = PAGE_SHIFT;
info.si_addr_lsb = lsb;

- fill_sig_info_pkey(si_code, &info, pkey);
+ fill_sig_info_pkey(si_signo, si_code, &info, pkey);

force_sig_info(si_signo, &info, tsk);
}

2018-01-15 16:30:39

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
> Setting si_code to 0 results in a userspace seeing an si_code of 0.
> This is the same si_code as SI_USER. Posix and common sense requires
> that SI_USER not be a signal specific si_code. As such this use of 0
> for the si_code is a pretty horribly broken ABI.

I think this situation may have come about because 0 is used as a
padding value for "impossible" cases -- i.e., things that can't happen
unless the kernel is broken, or things that are too unrecoverable for
clean error reporting to be helpful.

In general, I think these values are not expected to reach userspace in
practice.

This is not an excuse though -- and not 100% true -- so it's certainly
worthy of cleanup.


It would be good to approach this similarly for arm and arm64, since
the arm64 fault code is derived from arm.


> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
> value of __SI_KILL and now sees a value of SIL_KILL with the result
> that uid and pid fields are copied and which might copying the si_addr
> field by accident but certainly not by design. Making this a very
> flakey implementation.
>
> Utilizing FPE_FIXME, BUS_FIXME, TRAP_FIXME siginfo_layout will now return
> SIL_FAULT and the appropriate fields will be reliably copied.
>
> But folks this is a new and unique kind of bad. This is massively
> untested code bad. This is inventing new and unique was to get
> siginfo wrong bad. This is don't even think about Posix or what
> siginfo means bad. This is lots of eyeballs all missing the fact
> that the code does the wrong thing bad. This is getting stuck
> and keep making the same mistake bad.
>
> I really hope we can find a non userspace breaking fix for this on a
> port as new as arm64.

> Possible ABI fixes include:
> - Send the signal without siginfo
> - Don't generate a signal

The above two sould like ABI breaks?

> - Possibly assign and use an appropriate si_code
> - Don't handle cases which can't happen

I think a mixture of these two is the best approach.

In any case, si_code == 0 here doesn't seem to have any explicit meaning.
I think we can translate all of the arm64 faults to proper si_codes --
see my sketch below. Probably means a bit more thought though.



The only counterargument would be if there is software relying on
these bogus signal cases getting si_code == 0 for a useful purpose.

The main reason I see to check for SI_USER is to allow a process to
filter out spurious signals (say, an asynchronous I/O signal for
which si_value would be garbage), and to print out diagnostics
before (in the case of a well-behaved program) resetting the signal
to SIG_DFL and killing itself to report the signal to the waiter.

Daemons may be more discerning about who is allowed to signal them,
but overloading SIGBUS (say) as an IPC channel sounds like a very odd
thing to do. The same probably applies to any signal that has
nontrivial metadata.


Have you found software that is impacted by this in practice?

[...]

> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
> asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
> {
> siginfo_t info;
> - unsigned int si_code = 0;
> + unsigned int si_code = FPE_FIXME;
>
> if (esr & FPEXC_IOF)
> si_code = FPE_FLTINV;

This 0 can happen for vector operations where the implementation may
not be able to report exactly what happened, for example where
the implementer didn't want to pay the cost of tracking exactly
what went wrong in each lane.

However, the FPEXC_* bits can be garbage in such a case rather
than being all zero: we should be checking the TFV bit in the ESR here.
This may be a bug.

Perhaps FPE_FLTINV should be returned in si_code for such cases: it's
not otherwise used on arm64 -- invalid instructions would be reported as
SIGILL/ILL_ILLOPC instead).

Otherwise, we might want to define a new code or arbitrarily pick
one of the existing FLT_* since this is really a more benign condition
than executing an illegal instruction. Alternatively, treat the
fault as spurious and suppress it, but that doesn't feel right either.


> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index 9b7f89df49db..abe200587334 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
>
> info.si_signo = SIGBUS;
> info.si_errno = 0;
> - info.si_code = 0;
> + info.si_code = BUS_FIXME;

Probably BUS_OBJERR.

> if (esr & ESR_ELx_FnV)
> info.si_addr = NULL;
> else
> @@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
> }
>
> static const struct fault_info fault_info[] = {
> - { do_bad, SIGBUS, 0, "ttbr address size fault" },
> - { do_bad, SIGBUS, 0, "level 1 address size fault" },
> - { do_bad, SIGBUS, 0, "level 2 address size fault" },
> - { do_bad, SIGBUS, 0, "level 3 address size fault" },
> + { do_bad, SIGBUS, BUS_FIXME, "ttbr address size fault" },
> + { do_bad, SIGBUS, BUS_FIXME, "level 1 address size fault" },
> + { do_bad, SIGBUS, BUS_FIXME, "level 2 address size fault" },
> + { do_bad, SIGBUS, BUS_FIXME, "level 3 address size fault" },

Pagetable screwup or kernel/system/CPU bug -> SIGKILL, or panic().

[...]

> - { do_bad, SIGBUS, 0, "unknown 8" },
> + { do_bad, SIGBUS, BUS_FIXME, "unknown 8" },

[...]

> + { do_bad, SIGBUS, BUS_FIXME, "unknown 12" },

Not architected, so they could mean absolutely anything. If they
can happen at all, they are probably unsafe to ignore.

-> SIGKILL, or panic().

Similary for all the "unknown" codes in the table, which I omit for
brevity.

> + { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },

This si_code seems to be a fallback for if ACPI is absent or doesn't
know what to do with this error.

-> SIGBUS/BUS_OBJERR?

Can probably legitimately happen for userspace for suitable MMIO mappings.

Perhaps it's more serious though in the presence of ACPI. Do we expect
that ACPI can diagnose all localisable errors?

> + { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" },
> + { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" },
> + { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" },
> + { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },

Pagetable screwup or kernel/system/CPU bug -> SIGKILL, or panic().

> + { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implemented

Possibly SIGBUS/BUS_MCEERR_AR (though I don't know exactly what
userspace is supposed to do with this or whether this implies the
existence or certain kernel features for managing the error that
may not be present on arm64...)

Otherwise, SIGKILL.

> + { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
> + { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
> + { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
> + { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented

Process page tables corrupt: if the kernel couldn't fix this, the
process can't reasonably fix it -> SIGKILL

Since this is a RAS-type error it could be triggered by a cosmic ray
rather than requiring a kernel or system bug or other major failure, so
we probably shouldn't panic the system if the error is localisable to a
particular process.

> { do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" },
> + { do_bad, SIGBUS, BUS_FIXME, "TLB conflict abort" },

Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL or panic().

> + { do_bad, SIGBUS, BUS_FIXME, "Unsupported atomic hardware update fault" },

Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL or panic().

> + { do_bad, SIGBUS, BUS_FIXME, "implementation fault (lockdown abort)" },

Userspace shouldn't have access to lockdown: kernel/system bug
-> SIGKILL or panic().

> + { do_bad, SIGBUS, BUS_FIXME, "implementation fault (unsupported exclusive)" },

If running on an implementation where this fault can happen in response to an exclusive load/store issued by userspace may fail somewhere in the memory system, this should probably be SIGBUS/BUS_OBJERR (or possibly a new BUS_* code).

This one may need to be hardware-dependent, if this fault can mean
something different depending on the hardware (I'm gussing this
possibility from "implementation" -- I've not checked the docs.)

> + { do_bad, SIGBUS, BUS_FIXME, "section domain fault" },
> + { do_bad, SIGBUS, BUS_FIXME, "page domain fault" },

Broken kernel, kernel memory corruption, CPU/system bug etc.:
SIGKILL or panic().

> };
>
> int handle_guest_sea(phys_addr_t addr, unsigned int esr)
> @@ -739,11 +739,11 @@ static struct fault_info __refdata debug_fault_info[] = {
> + { do_bad, SIGBUS, BUS_FIXME, "unknown 3" },
> + { do_bad, SIGTRAP, TRAP_FIXME, "aarch32 vector catch" },
> + { do_bad, SIGBUS, BUS_FIXME, "unknown 7" },
> };

Impossible (?), or meaning unknown.
SIGKILL/panic() for these? Or possibly (since these are probably well
localised errors) SIGILL/ILL_ILLOPC.

Cheers
---Dave

2018-01-15 17:24:02

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

Dave Martin <[email protected]> writes:

> On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
>> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>> This is the same si_code as SI_USER. Posix and common sense requires
>> that SI_USER not be a signal specific si_code. As such this use of 0
>> for the si_code is a pretty horribly broken ABI.
>
> I think this situation may have come about because 0 is used as a
> padding value for "impossible" cases -- i.e., things that can't happen
> unless the kernel is broken, or things that are too unrecoverable for
> clean error reporting to be helpful.
>
> In general, I think these values are not expected to reach userspace in
> practice.
>
> This is not an excuse though -- and not 100% true -- so it's certainly
> worthy of cleanup.
>
>
> It would be good to approach this similarly for arm and arm64, since
> the arm64 fault code is derived from arm.

In this case the fault_info is something I have only seen on arm64.
I have been approaching all architectures the same way.

If there is insufficient information without architecture expertise
to fix this class of error I have been ading FPE_FIXME to them.

>> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>> value of __SI_KILL and now sees a value of SIL_KILL with the result
>> that uid and pid fields are copied and which might copying the si_addr
>> field by accident but certainly not by design. Making this a very
>> flakey implementation.
>>
>> Utilizing FPE_FIXME, BUS_FIXME, TRAP_FIXME siginfo_layout will now return
>> SIL_FAULT and the appropriate fields will be reliably copied.
>>
>> But folks this is a new and unique kind of bad. This is massively
>> untested code bad. This is inventing new and unique was to get
>> siginfo wrong bad. This is don't even think about Posix or what
>> siginfo means bad. This is lots of eyeballs all missing the fact
>> that the code does the wrong thing bad. This is getting stuck
>> and keep making the same mistake bad.
>>
>> I really hope we can find a non userspace breaking fix for this on a
>> port as new as arm64.
>
>> Possible ABI fixes include:
>> - Send the signal without siginfo
>> - Don't generate a signal
>
> The above two sould like ABI breaks?

They are ways I have seen code on other platforms deal with
not information to generate siginfo. Sending the signal without siginfo
is roughly equivalent to your send SIGKILL suggestion below.

A good example of that is code that calls force_sigsegv.

Calling "force_sig(SIGBUS, current);" is perfectly valid.
And then the parent when it reaped the process would have
a little more information to go on when guessing what happened
to the process.

>> - Possibly assign and use an appropriate si_code
>> - Don't handle cases which can't happen
>
> I think a mixture of these two is the best approach.
>
> In any case, si_code == 0 here doesn't seem to have any explicit meaning.
> I think we can translate all of the arm64 faults to proper si_codes --
> see my sketch below. Probably means a bit more thought though.

Yes I would be very happy to see that.

> The only counterargument would be if there is software relying on
> these bogus signal cases getting si_code == 0 for a useful purpose.
>
> The main reason I see to check for SI_USER is to allow a process to
> filter out spurious signals (say, an asynchronous I/O signal for
> which si_value would be garbage), and to print out diagnostics
> before (in the case of a well-behaved program) resetting the signal
> to SIG_DFL and killing itself to report the signal to the waiter.
>
> Daemons may be more discerning about who is allowed to signal them,
> but overloading SIGBUS (say) as an IPC channel sounds like a very odd
> thing to do. The same probably applies to any signal that has
> nontrivial metadata.

Agreed. Although I have seen ltp test cases that do crazy things like
that.

> Have you found software that is impacted by this in practice?

No.

I don't expect many userspace applications look at siginfo and
everything I have found is some rare hard to trigger non-x86 case which
limits the exposure to userspace applications tremendously.

The angle I am coming at all of this from is that the linux kernel code
that filled out out struct siginfo was not comprehensible or correct.
Internal to the kernel it was using a magic value (not exportable to
userspace) in the upper bits of si_code. That was causing problems for
signal injection and converting signals from 32bit to 64bit, and from
64bit to 32bit.

So I wrote kernel/signal.c:siginfo_layout() to figure out which fields
of struct siginfo should be sent to userspace. In doing so I discovered
that using 0 in si_code (aka SI_USER) is ambiguous, and problematic.

Unfortuantely in most of the cases I have spotted using 0 in the si_code
requires architectural knowledge that I don't currently have to sort
out. So the best I can do is change si_code from 0 to
FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers
attention to this area.

One of the problems that results from all of this is that we copy
unitialized data to userspace. I am slowly unifying and cleaning the
code up so that the code is simple enough we can be certain we are
not copying unitialized data to userspace.

With si_coes of FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to
keep the craziness from happening.

My next step is to unify struct siginfo and struct compat_siginfo
and the functions that copy them to userspace because there are very
siginficant problems there.


All of that said I like the way you are thinking about fixing these
issues.

> [...]
>
>> +++ b/arch/arm64/kernel/fpsimd.c
>> @@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
>> asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
>> {
>> siginfo_t info;
>> - unsigned int si_code = 0;
>> + unsigned int si_code = FPE_FIXME;
>>
>> if (esr & FPEXC_IOF)
>> si_code = FPE_FLTINV;
>
> This 0 can happen for vector operations where the implementation may
> not be able to report exactly what happened, for example where
> the implementer didn't want to pay the cost of tracking exactly
> what went wrong in each lane.
>
> However, the FPEXC_* bits can be garbage in such a case rather
> than being all zero: we should be checking the TFV bit in the ESR here.
> This may be a bug.
>
> Perhaps FPE_FLTINV should be returned in si_code for such cases: it's
> not otherwise used on arm64 -- invalid instructions would be reported as
> SIGILL/ILL_ILLOPC instead).
>
> Otherwise, we might want to define a new code or arbitrarily pick
> one of the existing FLT_* since this is really a more benign condition
> than executing an illegal instruction. Alternatively, treat the
> fault as spurious and suppress it, but that doesn't feel right either.

I would love to see this sorted out. There is a very similar pattern
on several different architectures. I suspect if we have a clean
solution on one architecture the other architectures will be able to use
that solution as well.

>> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
>> index 9b7f89df49db..abe200587334 100644
>> --- a/arch/arm64/mm/fault.c
>> +++ b/arch/arm64/mm/fault.c
>> @@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
>>
>> info.si_signo = SIGBUS;
>> info.si_errno = 0;
>> - info.si_code = 0;
>> + info.si_code = BUS_FIXME;
>
> Probably BUS_OBJERR.
>
>> if (esr & ESR_ELx_FnV)
>> info.si_addr = NULL;
>> else
>> @@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
>> }
>>
>> static const struct fault_info fault_info[] = {
>> - { do_bad, SIGBUS, 0, "ttbr address size fault" },
>> - { do_bad, SIGBUS, 0, "level 1 address size fault" },
>> - { do_bad, SIGBUS, 0, "level 2 address size fault" },
>> - { do_bad, SIGBUS, 0, "level 3 address size fault" },
>> + { do_bad, SIGBUS, BUS_FIXME, "ttbr address size fault" },
>> + { do_bad, SIGBUS, BUS_FIXME, "level 1 address size fault" },
>> + { do_bad, SIGBUS, BUS_FIXME, "level 2 address size fault" },
>> + { do_bad, SIGBUS, BUS_FIXME, "level 3 address size fault" },
>
> Pagetable screwup or kernel/system/CPU bug -> SIGKILL, or panic().
>
> [...]
>
>> - { do_bad, SIGBUS, 0, "unknown 8" },
>> + { do_bad, SIGBUS, BUS_FIXME, "unknown 8" },
>
> [...]
>
>> + { do_bad, SIGBUS, BUS_FIXME, "unknown 12" },
>
> Not architected, so they could mean absolutely anything. If they
> can happen at all, they are probably unsafe to ignore.
>
> -> SIGKILL, or panic().
>
> Similary for all the "unknown" codes in the table, which I omit for
> brevity.
>
>> + { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },
>
> This si_code seems to be a fallback for if ACPI is absent or doesn't
> know what to do with this error.
>
> -> SIGBUS/BUS_OBJERR?
>
> Can probably legitimately happen for userspace for suitable MMIO mappings.
>
> Perhaps it's more serious though in the presence of ACPI. Do we expect
> that ACPI can diagnose all localisable errors?
>
>> + { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" },
>> + { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" },
>> + { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" },
>> + { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },
>
> Pagetable screwup or kernel/system/CPU bug -> SIGKILL, or panic().
>
>> + { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implemented
>
> Possibly SIGBUS/BUS_MCEERR_AR (though I don't know exactly what
> userspace is supposed to do with this or whether this implies the
> existence or certain kernel features for managing the error that
> may not be present on arm64...)
>
> Otherwise, SIGKILL.

Yes. The AR Action Required and AO Action optional bits I don't quite
understand. But BUS_MCEERR_AR does sound like a good fit.


>> + { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>> + { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>> + { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>> + { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>
> Process page tables corrupt: if the kernel couldn't fix this, the
> process can't reasonably fix it -> SIGKILL
>
> Since this is a RAS-type error it could be triggered by a cosmic ray
> rather than requiring a kernel or system bug or other major failure, so
> we probably shouldn't panic the system if the error is localisable to a
> particular process.
>
>> { do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" },
>> + { do_bad, SIGBUS, BUS_FIXME, "TLB conflict abort" },
>
> Broken kernel, kernel memory corruption, CPU/system bug etc.:
> SIGKILL or panic().
>
>> + { do_bad, SIGBUS, BUS_FIXME, "Unsupported atomic hardware update fault" },
>
> Broken kernel, kernel memory corruption, CPU/system bug etc.:
> SIGKILL or panic().
>
>> + { do_bad, SIGBUS, BUS_FIXME, "implementation fault (lockdown abort)" },
>
> Userspace shouldn't have access to lockdown: kernel/system bug
> -> SIGKILL or panic().
>
>> + { do_bad, SIGBUS, BUS_FIXME, "implementation fault (unsupported exclusive)" },
>
> If running on an implementation where this fault can happen in response to an exclusive load/store issued by userspace may fail somewhere in the memory system, this should probably be SIGBUS/BUS_OBJERR (or possibly a new BUS_* code).
>
> This one may need to be hardware-dependent, if this fault can mean
> something different depending on the hardware (I'm gussing this
> possibility from "implementation" -- I've not checked the docs.)
>
>> + { do_bad, SIGBUS, BUS_FIXME, "section domain fault" },
>> + { do_bad, SIGBUS, BUS_FIXME, "page domain fault" },
>
> Broken kernel, kernel memory corruption, CPU/system bug etc.:
> SIGKILL or panic().
>
>> };
>>
>> int handle_guest_sea(phys_addr_t addr, unsigned int esr)
>> @@ -739,11 +739,11 @@ static struct fault_info __refdata debug_fault_info[] = {
>> + { do_bad, SIGBUS, BUS_FIXME, "unknown 3" },
>> + { do_bad, SIGTRAP, TRAP_FIXME, "aarch32 vector catch" },
>> + { do_bad, SIGBUS, BUS_FIXME, "unknown 7" },
>> };
>
> Impossible (?), or meaning unknown.
> SIGKILL/panic() for these? Or possibly (since these are probably well
> localised errors) SIGILL/ILL_ILLOPC.

I like the way you are thinking on these, and I'd love to see them
fixed.

Eric

2018-01-15 17:49:57

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE

On Thu, Jan 11, 2018 at 06:59:37PM -0600, Eric W. Biederman wrote:
> Setting si_code to 0 results in a userspace seeing an si_code of 0.
> This is the same si_code as SI_USER. Posix and common sense requires
> that SI_USER not be a signal specific si_code. As such this use of 0
> for the si_code is a pretty horribly broken ABI.
>
> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
> value of __SI_KILL and now sees a value of SIL_KILL with the result
> that uid and pid fields are copied and which might copying the si_addr
> field by accident but certainly not by design. Making this a very
> flakey implementation.
>
> Utilizing FPE_FIXME, siginfo_layout will now return SIL_FAULT and the
> appropriate fields will be reliably copied.

So what do you suggest when none of the SIGFPE FPE_xxx codes match the
condition that "we don't know what happened" ? Raise a SIGKILL instead
maybe? We will have dumped the VFP state into the kernel log at this
point, things are pretty much fscked.

It's probably an impossible condition unless the hardware has failed,
no one has knowingly reported getting such a dump in their kernel log,
so it's something that could very likely be changed in some way
without anyone noticing.

--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

2018-01-15 19:32:50

by James Morse

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

Hi Dave,

Thanks for going through all these,

On 15/01/18 16:30, Dave Martin wrote:
> On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
>> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
>> index 9b7f89df49db..abe200587334 100644
>> --- a/arch/arm64/mm/fault.c
>> +++ b/arch/arm64/mm/fault.c
>> @@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)

>> + { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },
>
> This si_code seems to be a fallback for if ACPI is absent or doesn't
> know what to do with this error.
>
> -> SIGBUS/BUS_OBJERR?
>
> Can probably legitimately happen for userspace for suitable MMIO mappings.

It can happen for normal memory too, there are specific ESR values for
parity/checksum errors when read/writing memory. I think this first one is
'other/unknown', and its up to the CPU how to classify them.


> Perhaps it's more serious though in the presence of ACPI. Do we expect
> that ACPI can diagnose all localisable errors?

Its not just ACPI, the CPU's v8.2 RAS Extensions use this
synchronous-external-abort as notification of a RAS error, (the other details
are written to to memory-mapped nodes). With the v8.2 RAS Extensions the ESR
tells us if the error was contained.

For ACPI we rely on firmware to set an appropriate severity in the CPER records
generated by firmware. The APEI helpers will call panic() if they find a fatal
error.

For systems with neither {firmware,kernel}-first RAS, BUS_OBJERR looks like a
good choice.


>> + { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" },
>> + { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" },
>> + { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" },
>> + { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },
>
> Pagetable screwup or kernel/system/CPU bug -> SIGKILL, or panic().

(RAS mechanisms may claim this and send their own signals, if not:)

SIGKILL is probably a better choice here, while we do have an address, there is
nothing user-space can do about it.


>> + { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implemented
>
> Possibly SIGBUS/BUS_MCEERR_AR (though I don't know exactly what
> userspace is supposed to do with this or whether this implies the
> existence or certain kernel features for managing the error that
> may not be present on arm64...)

I'd like to keep the MCEERR signals to errors that we know are contained, the
kernel has understood and handled.

(These features do exist for arm64, enabling CONFIG_MEMORY_FAILURE and a few
APEI options allows all this to work today with suitable firmware. My Seattle
claims to support it).


> Otherwise, SIGKILL.

Sounds good,


>> + { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>> + { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>> + { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>> + { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
>
> Process page tables corrupt: if the kernel couldn't fix this, the
> process can't reasonably fix it -> SIGKILL
>
> Since this is a RAS-type error it could be triggered by a cosmic ray
> rather than requiring a kernel or system bug or other major failure, so
> we probably shouldn't panic the system if the error is localisable to a
> particular process.

Without the RAS-Extensions severity to tell us the error is contained I'm not
sure what we can expect. But given the page-tables are per-process, and we never
swap them to disk etc, its probably a safe bet that it doesn't matter either way
for these.


Thanks,

James

2018-01-15 20:13:23

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE

Russell King - ARM Linux <[email protected]> writes:

> On Thu, Jan 11, 2018 at 06:59:37PM -0600, Eric W. Biederman wrote:
>> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>> This is the same si_code as SI_USER. Posix and common sense requires
>> that SI_USER not be a signal specific si_code. As such this use of 0
>> for the si_code is a pretty horribly broken ABI.
>>
>> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>> value of __SI_KILL and now sees a value of SIL_KILL with the result
>> that uid and pid fields are copied and which might copying the si_addr
>> field by accident but certainly not by design. Making this a very
>> flakey implementation.
>>
>> Utilizing FPE_FIXME, siginfo_layout will now return SIL_FAULT and the
>> appropriate fields will be reliably copied.
>
> So what do you suggest when none of the SIGFPE FPE_xxx codes match the
> condition that "we don't know what happened" ? Raise a SIGKILL instead
> maybe? We will have dumped the VFP state into the kernel log at this
> point, things are pretty much fscked.
>
> It's probably an impossible condition unless the hardware has failed,
> no one has knowingly reported getting such a dump in their kernel log,
> so it's something that could very likely be changed in some way
> without anyone noticing.

It sounds like we have two equally valid possible solutions:
1) force_sig(SIGKILL, current);
2) Allocate a new FPE_xxx code in asm-generic/siginfo.h
I believe the next available number is 15.

If no one is going to notice this should be comparatively easy to fix.
I just don't have the knowledge of arm to make the judgement myself.

Eric

2018-01-16 00:40:23

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 00/22] siginfo unification


The following changes are available at:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git siginfo-testing

This set of changes unifies struct siginfo and struct compat_siginfo so
that there is only one definition of each. Additionally this ends up
with a single implementation of copy_siginfo_to_user32 and
copy_siginfo_from_user32.

This results in much less code, that might be slightly less readable as
it handles all of the cases it needs to deal with instead of just a few.
Not a single implementation of copy_siginfo_to_user32 or
copy_siginfo_from_user32 handled all of the ways data is encoded in
struct siginfo today.

Hopefully this will result in much more maintainable code.

Al Viro (3):
signal/mips: switch mips to generic siginfo
signal: kill __ARCH_SI_UID_T
signal: unify compat_siginfo_t

Eric W. Biederman (19):
signal: Document all of the signals that use the _sigfault union member
signal: Document the strange si_codes used by ptrace event stops
signal: Document glibc's si_code of SI_ASYNCNL
signal: Ensure no siginfo union member increases the size of struct siginfo
signal: Clear si_sys_private before copying siginfo to userspace
signal: Remove _sys_private and _overrun_incr from struct compat_siginfo
ia64/signal: switch to generic struct siginfo
signal/ia64: switch the last arch-specific copy_siginfo_to_user() to generic version
signal: Remove unnecessary ifdefs now that there is only one struct siginfo
signal: Move addr_lsb into the _sigfault union for clarity
signal/powerpc: Remove redefinition of NSIGTRAP on powerpc
signal/ia64: Move the ia64 specific si_codes to asm-generic/siginfo.h
signal/frv: Move the frv specific si_codes to asm-generic/siginfo.h
signal/tile: Move the tile specific si_codes to asm-generic/siginfo.h
signal/blackfin: Move the blackfin specific si_codes to asm-generic/siginfo.h
signal/blackfin: Remove pointless UID16_SIGINFO_COMPAT_NEEDED
signal: Unify and correct copy_siginfo_from_user32
signal: Remove the code to clear siginfo before calling copy_siginfo_from_user32
signal: Unify and correct copy_siginfo_to_user32

arch/arm64/include/asm/compat.h | 64 ----------
arch/arm64/kernel/signal32.c | 80 -------------
arch/blackfin/include/uapi/asm/siginfo.h | 34 ------
arch/frv/include/uapi/asm/Kbuild | 1 +
arch/frv/include/uapi/asm/siginfo.h | 13 --
arch/ia64/include/uapi/asm/siginfo.h | 96 ---------------
arch/ia64/kernel/signal.c | 52 --------
arch/mips/include/asm/compat.h | 73 ------------
arch/mips/include/uapi/asm/siginfo.h | 86 +-------------
arch/mips/kernel/signal32.c | 67 -----------
arch/parisc/include/asm/compat.h | 64 ----------
arch/parisc/kernel/signal32.c | 106 -----------------
arch/parisc/kernel/signal32.h | 3 -
arch/powerpc/include/asm/compat.h | 65 ----------
arch/powerpc/include/uapi/asm/siginfo.h | 3 -
arch/powerpc/kernel/signal_32.c | 66 -----------
arch/s390/include/asm/compat.h | 73 ------------
arch/s390/kernel/compat_signal.c | 100 ----------------
arch/sparc/include/asm/compat.h | 59 ---------
arch/sparc/kernel/signal32.c | 69 -----------
arch/tile/include/asm/compat.h | 62 ----------
arch/tile/include/uapi/asm/siginfo.h | 8 --
arch/tile/kernel/compat_signal.c | 73 ------------
arch/x86/include/asm/compat.h | 86 +-------------
arch/x86/include/asm/fpu/signal.h | 6 -
arch/x86/kernel/signal_compat.c | 123 ++-----------------
include/linux/compat.h | 100 +++++++++++++++-
include/linux/signal.h | 2 -
include/uapi/asm-generic/siginfo.h | 109 +++++++++++++----
kernel/ptrace.c | 1 -
kernel/signal.c | 197 +++++++++++++++++++++++++++++--
31 files changed, 382 insertions(+), 1559 deletions(-)

Eric

2018-01-16 00:41:32

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 01/22] signal: Document all of the signals that use the _sigfault union member

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/uapi/asm-generic/siginfo.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index e447283b8f52..cbe1b0cc7a6a 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -85,7 +85,7 @@ typedef struct siginfo {
__ARCH_SI_CLOCK_T _stime;
} _sigchld;

- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */
struct {
void __user *_addr; /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
--
2.14.1

2018-01-16 00:41:35

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 02/22] signal: Document the strange si_codes used by ptrace event stops

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/uapi/asm-generic/siginfo.h | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index cbe1b0cc7a6a..7158421ac911 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -225,6 +225,11 @@ typedef struct siginfo {
#define TRAP_HWBKPT 4 /* hardware breakpoint/watchpoint */
#define NSIGTRAP 4

+/*
+ * There are an additional set of SIGTRAP si_codes used by ptrace
+ * that of the form: ((PTRACE_EVENT_XXX << 8) | SIGTRAP)
+ */
+
/*
* SIGCHLD si_codes
*/
--
2.14.1

2018-01-16 00:41:40

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 04/22] signal: Ensure no siginfo union member increases the size of struct siginfo

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
kernel/signal.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/kernel/signal.c b/kernel/signal.c
index 241d54958bbb..b9e5d825ee46 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3688,6 +3688,7 @@ void __init signals_init(void)
/* If this check fails, the __ARCH_SI_PREAMBLE_SIZE value is wrong! */
BUILD_BUG_ON(__ARCH_SI_PREAMBLE_SIZE
!= offsetof(struct siginfo, _sifields._pad));
+ BUILD_BUG_ON(sizeof(struct siginfo) != SI_MAX_SIZE);

sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);
}
--
2.14.1

2018-01-16 00:41:51

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 09/22] signal/mips: switch mips to generic siginfo

From: Al Viro <[email protected]>

... having taught the latter that si_errno and si_code might be
swapped.

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
arch/mips/include/uapi/asm/siginfo.h | 86 +-----------------------------------
include/uapi/asm-generic/siginfo.h | 5 +++
2 files changed, 6 insertions(+), 85 deletions(-)

diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h
index f17d8163dec6..262504bd59a5 100644
--- a/arch/mips/include/uapi/asm/siginfo.h
+++ b/arch/mips/include/uapi/asm/siginfo.h
@@ -14,8 +14,6 @@
#define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(long) + 2*sizeof(int))
#undef __ARCH_SI_TRAPNO /* exception code needs to fill this ... */

-#define HAVE_ARCH_SIGINFO_T
-
/*
* Careful to keep union _sifields from shifting ...
*/
@@ -27,92 +25,10 @@
#error _MIPS_SZLONG neither 32 nor 64
#endif

-#define __ARCH_SIGSYS
+#define __ARCH_HAS_SWAPPED_SIGINFO

#include <asm-generic/siginfo.h>

-/* We can't use generic siginfo_t, because our si_code and si_errno are swapped */
-typedef struct siginfo {
- int si_signo;
- int si_code;
- int si_errno;
- int __pad0[SI_MAX_SIZE / sizeof(int) - SI_PAD_SIZE - 3];
-
- union {
- int _pad[SI_PAD_SIZE];
-
- /* kill() */
- struct {
- __kernel_pid_t _pid; /* sender's pid */
- __ARCH_SI_UID_T _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- __kernel_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
- sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- __kernel_pid_t _pid; /* sender's pid */
- __ARCH_SI_UID_T _uid; /* sender's uid */
- sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- __kernel_pid_t _pid; /* which child */
- __ARCH_SI_UID_T _uid; /* sender's uid */
- int _status; /* exit code */
- __kernel_clock_t _utime;
- __kernel_clock_t _stime;
- } _sigchld;
-
- /* IRIX SIGCHLD */
- struct {
- __kernel_pid_t _pid; /* which child */
- __kernel_clock_t _utime;
- int _status; /* exit code */
- __kernel_clock_t _stime;
- } _irix_sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- void __user *_addr; /* faulting insn/memory ref. */
-#ifdef __ARCH_SI_TRAPNO
- int _trapno; /* TRAP # which caused the signal */
-#endif
- short _addr_lsb;
- union {
- /* used when si_code=SEGV_BNDERR */
- struct {
- void __user *_lower;
- void __user *_upper;
- } _addr_bnd;
- /* used when si_code=SEGV_PKUERR */
- __u32 _pkey;
- };
- } _sigfault;
-
- /* SIGPOLL, SIGXFSZ (To do ...) */
- struct {
- __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
-
- /* SIGSYS */
- struct {
- void __user *_call_addr; /* calling user insn */
- int _syscall; /* triggering system call number */
- unsigned int _arch; /* AUDIT_ARCH_* of syscall */
- } _sigsys;
- } _sifields;
-} siginfo_t;
-
/*
* si_code values
* Again these have been chosen to be IRIX compatible.
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 1555805c5ac8..00829f74dcb6 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -48,8 +48,13 @@ typedef union sigval {

typedef struct siginfo {
int si_signo;
+#ifndef __ARCH_HAS_SWAPPED_SIGINFO
int si_errno;
int si_code;
+#else
+ int si_code;
+ int si_errno;
+#endif

union {
int _pad[SI_PAD_SIZE];
--
2.14.1

2018-01-16 00:42:08

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 10/22] signal: Remove unnecessary ifdefs now that there is only one struct siginfo

Remove HAVE_ARCH_SIGINFO_T
Remove __ARCH_SIGSYS

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/linux/signal.h | 2 --
include/uapi/asm-generic/siginfo.h | 8 --------
kernel/signal.c | 4 ----
3 files changed, 14 deletions(-)

diff --git a/include/linux/signal.h b/include/linux/signal.h
index 87abf0c29ed7..a9bc7e1b077e 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -30,9 +30,7 @@ enum siginfo_layout {
SIL_FAULT,
SIL_CHLD,
SIL_RT,
-#ifdef __ARCH_SIGSYS
SIL_SYS,
-#endif
};

enum siginfo_layout siginfo_layout(int sig, int si_code);
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 00829f74dcb6..a650d252de0a 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -44,8 +44,6 @@ typedef union sigval {
#define __ARCH_SI_ATTRIBUTES
#endif

-#ifndef HAVE_ARCH_SIGINFO_T
-
typedef struct siginfo {
int si_signo;
#ifndef __ARCH_HAS_SWAPPED_SIGINFO
@@ -128,10 +126,6 @@ typedef struct siginfo {
} _sifields;
} __ARCH_SI_ATTRIBUTES siginfo_t;

-/* If the arch shares siginfo, then it has SIGSYS. */
-#define __ARCH_SIGSYS
-#endif
-
/*
* How these fields are to be accessed.
*/
@@ -156,11 +150,9 @@ typedef struct siginfo {
#define si_pkey _sifields._sigfault._pkey
#define si_band _sifields._sigpoll._band
#define si_fd _sifields._sigpoll._fd
-#ifdef __ARCH_SIGSYS
#define si_call_addr _sifields._sigsys._call_addr
#define si_syscall _sifields._sigsys._syscall
#define si_arch _sifields._sigsys._arch
-#endif

/*
* si_code values
diff --git a/kernel/signal.c b/kernel/signal.c
index 62c642899290..47c87b1d0b8a 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2697,9 +2697,7 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
#endif
[SIGCHLD] = { NSIGCHLD, SIL_CHLD },
[SIGPOLL] = { NSIGPOLL, SIL_POLL },
-#ifdef __ARCH_SIGSYS
[SIGSYS] = { NSIGSYS, SIL_SYS },
-#endif
};
if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit))
layout = filter[sig].layout;
@@ -2804,13 +2802,11 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_ptr, &to->si_ptr);
break;
-#ifdef __ARCH_SIGSYS
case SIL_SYS:
err |= __put_user(from->si_call_addr, &to->si_call_addr);
err |= __put_user(from->si_syscall, &to->si_syscall);
err |= __put_user(from->si_arch, &to->si_arch);
break;
-#endif
}
return err;
}
--
2.14.1

2018-01-16 00:41:44

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 06/22] signal: Remove _sys_private and _overrun_incr from struct compat_siginfo

We have never passed either field to or from userspace so just remove them.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arm64/include/asm/compat.h | 1 -
arch/parisc/include/asm/compat.h | 1 -
arch/powerpc/include/asm/compat.h | 1 -
arch/s390/include/asm/compat.h | 1 -
arch/sparc/include/asm/compat.h | 1 -
arch/tile/include/asm/compat.h | 2 --
arch/x86/include/asm/compat.h | 2 --
arch/x86/kernel/signal_compat.c | 2 +-
8 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index a3c7f271ad4c..dd32fe19ec58 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -174,7 +174,6 @@ typedef struct compat_siginfo {
compat_timer_t _tid; /* timer id */
int _overrun; /* overrun count */
compat_sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
} _timer;

/* POSIX.1b signals */
diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h
index acf8aa07cbe0..cf3bcacec027 100644
--- a/arch/parisc/include/asm/compat.h
+++ b/arch/parisc/include/asm/compat.h
@@ -155,7 +155,6 @@ typedef struct compat_siginfo {
int _overrun; /* overrun count */
char _pad[sizeof(unsigned int) - sizeof(int)];
compat_sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
} _timer;

/* POSIX.1b signals */
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index 8a2aecfe9b02..e02de2fd56e3 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -145,7 +145,6 @@ typedef struct compat_siginfo {
compat_timer_t _tid; /* timer id */
int _overrun; /* overrun count */
compat_sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
} _timer;

/* POSIX.1b signals */
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index 5e6a63641a5f..3a187c4932a5 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -213,7 +213,6 @@ typedef struct compat_siginfo {
compat_timer_t _tid; /* timer id */
int _overrun; /* overrun count */
compat_sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
} _timer;

/* POSIX.1b signals */
diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h
index fa38c78de0f0..2d9f4fd5f74a 100644
--- a/arch/sparc/include/asm/compat.h
+++ b/arch/sparc/include/asm/compat.h
@@ -175,7 +175,6 @@ typedef struct compat_siginfo {
compat_timer_t _tid; /* timer id */
int _overrun; /* overrun count */
compat_sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
} _timer;

/* POSIX.1b signals */
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index 62a7b83025dd..59ab9fa784b3 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -136,8 +136,6 @@ typedef struct compat_siginfo {
compat_timer_t _tid; /* timer id */
int _overrun; /* overrun count */
compat_sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
- int _overrun_incr; /* amount to add to overrun */
} _timer;

/* POSIX.1b signals */
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 2cbd75dd2fd3..1b6886a78562 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -151,8 +151,6 @@ typedef struct compat_siginfo {
compat_timer_t _tid; /* timer id */
int _overrun; /* overrun count */
compat_sigval_t _sigval; /* same as below */
- int _sys_private; /* not to be passed to user */
- int _overrun_incr; /* amount to add to overrun */
} _timer;

/* POSIX.1b signals */
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index 8c6da1a643da..85425ea30661 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -64,7 +64,7 @@ static inline void signal_compat_build_tests(void)
CHECK_SI_SIZE (_kill, 2*sizeof(int));

CHECK_CSI_OFFSET(_timer);
- CHECK_CSI_SIZE (_timer, 5*sizeof(int));
+ CHECK_CSI_SIZE (_timer, 3*sizeof(int));
CHECK_SI_SIZE (_timer, 6*sizeof(int));

CHECK_CSI_OFFSET(_rt);
--
2.14.1

2018-01-16 00:42:31

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 08/22] signal/ia64: switch the last arch-specific copy_siginfo_to_user() to generic version

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/ia64/include/uapi/asm/siginfo.h | 2 --
arch/ia64/kernel/signal.c | 52 ------------------------------------
kernel/signal.c | 9 ++++---
3 files changed, 5 insertions(+), 58 deletions(-)

diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h
index 3c5417d66628..66839031b767 100644
--- a/arch/ia64/include/uapi/asm/siginfo.h
+++ b/arch/ia64/include/uapi/asm/siginfo.h
@@ -11,8 +11,6 @@

#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))

-#define HAVE_ARCH_COPY_SIGINFO_TO_USER
-
#include <asm-generic/siginfo.h>

#define si_imm _sifields._sigfault._imm /* as per UNIX SysV ABI spec */
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index a254cc98f95c..54547c7cf8a2 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -105,58 +105,6 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
return err;
}

-int
-copy_siginfo_to_user (siginfo_t __user *to, const siginfo_t *from)
-{
- if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t)))
- return -EFAULT;
- if (from->si_code < 0) {
- if (__copy_to_user(to, from, sizeof(siginfo_t)))
- return -EFAULT;
- return 0;
- } else {
- int err;
-
- /*
- * If you change siginfo_t structure, please be sure this code is fixed
- * accordingly. It should never copy any pad contained in the structure
- * to avoid security leaks, but must copy the generic 3 ints plus the
- * relevant union member.
- */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
- switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_FAULT:
- err |= __put_user(from->si_flags, &to->si_flags);
- err |= __put_user(from->si_isr, &to->si_isr);
- case SIL_POLL:
- err |= __put_user(from->si_addr, &to->si_addr);
- err |= __put_user(from->si_imm, &to->si_imm);
- break;
- case SIL_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(from->si_ptr, &to->si_ptr);
- break;
- case SIL_RT:
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_ptr, &to->si_ptr);
- break;
- case SIL_CHLD:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- case SIL_KILL:
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_pid, &to->si_pid);
- break;
- }
- return err;
- }
-}
-
long
ia64_rt_sigreturn (struct sigscratch *scr)
{
diff --git a/kernel/signal.c b/kernel/signal.c
index 18aa55c1bb4f..62c642899290 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2729,8 +2729,6 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
return layout;
}

-#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER
-
int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
{
int err;
@@ -2769,6 +2767,11 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
#ifdef __ARCH_SI_TRAPNO
err |= __put_user(from->si_trapno, &to->si_trapno);
#endif
+#ifdef __ia64__
+ err |= __put_user(from->si_imm, &to->si_imm);
+ err |= __put_user(from->si_flags, &to->si_flags);
+ err |= __put_user(from->si_isr, &to->si_isr);
+#endif
#ifdef BUS_MCEERR_AO
/*
* Other callers might not initialize the si_lsb field,
@@ -2812,8 +2815,6 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
return err;
}

-#endif
-
/**
* do_sigtimedwait - wait for queued signals specified in @which
* @which: queued signals to wait for
--
2.14.1

2018-01-16 00:42:57

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 07/22] ia64/signal: switch to generic struct siginfo

... at a cost of added small ifdef __ia64__ in asm-generic siginfo.h,
that is.

-- EWB Corrected the comment on _flags to reflect the move

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/ia64/include/uapi/asm/siginfo.h | 67 ------------------------------------
include/uapi/asm-generic/siginfo.h | 5 +++
2 files changed, 5 insertions(+), 67 deletions(-)

diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h
index f3a02a10c3a3..3c5417d66628 100644
--- a/arch/ia64/include/uapi/asm/siginfo.h
+++ b/arch/ia64/include/uapi/asm/siginfo.h
@@ -11,77 +11,10 @@

#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))

-#define HAVE_ARCH_SIGINFO_T
#define HAVE_ARCH_COPY_SIGINFO_TO_USER

#include <asm-generic/siginfo.h>

-typedef struct siginfo {
- int si_signo;
- int si_errno;
- int si_code;
- int __pad0;
-
- union {
- int _pad[SI_PAD_SIZE];
-
- /* kill() */
- struct {
- pid_t _pid; /* sender's pid */
- uid_t _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- char _pad[sizeof(__ARCH_SI_UID_T) - sizeof(int)];
- sigval_t _sigval; /* must overlay ._rt._sigval! */
- int _sys_private; /* not to be passed to user */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- pid_t _pid; /* sender's pid */
- uid_t _uid; /* sender's uid */
- sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- pid_t _pid; /* which child */
- uid_t _uid; /* sender's uid */
- int _status; /* exit code */
- clock_t _utime;
- clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- void __user *_addr; /* faulting insn/memory ref. */
- int _imm; /* immediate value for "break" */
- unsigned int _flags; /* see below */
- unsigned long _isr; /* isr */
- short _addr_lsb; /* lsb of faulting address */
- union {
- /* used when si_code=SEGV_BNDERR */
- struct {
- void __user *_lower;
- void __user *_upper;
- } _addr_bnd;
- /* used when si_code=SEGV_PKUERR */
- __u32 _pkey;
- };
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */
- int _fd;
- } _sigpoll;
- } _sifields;
-} siginfo_t;
-
#define si_imm _sifields._sigfault._imm /* as per UNIX SysV ABI spec */
#define si_flags _sifields._sigfault._flags
/*
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 2d3348afb2f0..1555805c5ac8 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -90,6 +90,11 @@ typedef struct siginfo {
void __user *_addr; /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
int _trapno; /* TRAP # which caused the signal */
+#endif
+#ifdef __ia64__
+ int _imm; /* immediate value for "break" */
+ unsigned int _flags; /* see ia64 si_flags */
+ unsigned long _isr; /* isr */
#endif
short _addr_lsb; /* LSB of the reported address */
union {
--
2.14.1

2018-01-16 00:43:21

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 05/22] signal: Clear si_sys_private before copying siginfo to userspace

In preparation for unconditionally copying the whole of siginfo
to userspace clear si_sys_private. So this kernel internal
value is guaranteed not to make it to userspace.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
kernel/signal.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/kernel/signal.c b/kernel/signal.c
index b9e5d825ee46..18aa55c1bb4f 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -643,6 +643,9 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
spin_unlock(&tsk->sighand->siglock);
posixtimer_rearm(info);
spin_lock(&tsk->sighand->siglock);
+
+ /* Don't expose the si_sys_private value to userspace */
+ info->si_sys_private = 0;
}
#endif
return signr;
--
2.14.1

2018-01-16 00:43:43

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 22/22] signal: Unify and correct copy_siginfo_to_user32

Among the existing architecture specific versions of
copy_siginfo_to_user32 there are several different implementation
problems. Some architectures fail to handle all of the cases in in
the siginfo union. Some architectures perform a blind copy of the
siginfo union when the si_code is negative. A blind copy suggests the
data is expected to be in 32bit siginfo format, which means that
receiving such a signal via signalfd won't work, or that the data is
in 64bit siginfo and the code is copying nonsense to userspace.

Create a single instance of copy_siginfo_to_user32 that all of the
architectures can share, and teach it to handle all of the cases in
the siginfo union correctly, with the assumption that siginfo is
stored internally to the kernel is 64bit siginfo format.

A special case is made for x86 x32 format. This is needed as presence
of both x32 and ia32 on x86_64 results in two different 32bit signal
formats. By allowing this small special case there winds up being
exactly one code base that needs to be maintained between all of the
architectures. Vastly increasing the testing base and the chances of
finding bugs.

As the x86 copy of copy_siginfo_to_user32 the call of the x86
signal_compat_build_tests were moved into sigaction_compat_abi, so
that they will keep running.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arm64/kernel/signal32.c | 70 ----------------------------
arch/mips/include/asm/compat.h | 2 -
arch/mips/kernel/signal32.c | 57 -----------------------
arch/parisc/kernel/signal32.c | 62 -------------------------
arch/parisc/kernel/signal32.h | 2 -
arch/powerpc/include/asm/compat.h | 2 -
arch/powerpc/kernel/signal_32.c | 57 -----------------------
arch/s390/kernel/compat_signal.c | 52 ---------------------
arch/sparc/include/asm/compat.h | 2 -
arch/sparc/kernel/signal32.c | 53 ---------------------
arch/tile/include/asm/compat.h | 2 -
arch/tile/kernel/compat_signal.c | 55 ----------------------
arch/x86/include/asm/compat.h | 4 ++
arch/x86/include/asm/fpu/signal.h | 6 ---
arch/x86/kernel/signal_compat.c | 96 +--------------------------------------
kernel/signal.c | 90 ++++++++++++++++++++++++++++++++++++
16 files changed, 96 insertions(+), 516 deletions(-)

diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 4377907dbb70..cbc4edd1b1eb 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -125,76 +125,6 @@ static inline int get_sigset_t(sigset_t *set,
return 0;
}

-int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, to, sizeof(*to)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please be sure
- * this code is fixed accordingly.
- * It should never copy any pad contained in the structure
- * to avoid security leaks, but must copy the generic
- * 3 ints plus the relevant union member.
- * This routine must convert siginfo from 64bit to 32bit as well
- * at the same time.
- */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
- if (from->si_code < 0)
- err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
- SI_PAD_SIZE);
- else switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_KILL:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case SIL_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case SIL_POLL:
- err |= __put_user(from->si_band, &to->si_band);
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case SIL_FAULT:
- err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
- &to->si_addr);
-#ifdef BUS_MCEERR_AO
- /*
- * Other callers might not initialize the si_lsb field,
- * so check explicitly for the right codes here.
- */
- if (from->si_signo == SIGBUS &&
- (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
- err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
-#endif
- break;
- case SIL_CHLD:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_status, &to->si_status);
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- break;
- case SIL_RT:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case SIL_SYS:
- err |= __put_user((compat_uptr_t)(unsigned long)
- from->si_call_addr, &to->si_call_addr);
- err |= __put_user(from->si_syscall, &to->si_syscall);
- err |= __put_user(from->si_arch, &to->si_arch);
- break;
- }
- return err;
-}
-
/*
* VFP save/restore code.
*
diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
index fe7d445f675f..946681db8dc3 100644
--- a/arch/mips/include/asm/compat.h
+++ b/arch/mips/include/asm/compat.h
@@ -126,8 +126,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */

typedef u32 compat_sigset_word;

-#define SI_PAD_SIZE32 (128/sizeof(int) - 3)
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 500b5e4634ea..c4db910a8794 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -76,60 +76,3 @@ SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *,

return ret;
}
-
-int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
-{
- int err;
-
- if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please be sure
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member.
- This routine must convert siginfo from 64bit to 32bit as well
- at the same time. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
- if (from->si_code < 0)
- err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
- else {
- switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case SIL_CHLD:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- case SIL_KILL:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case SIL_FAULT:
- err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
- break;
- case SIL_POLL:
- err |= __put_user(from->si_band, &to->si_band);
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case SIL_RT:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case SIL_SYS:
- err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr,
- sizeof(compat_uptr_t));
- err |= __put_user(from->si_syscall, &to->si_syscall);
- err |= __put_user(from->si_arch, &to->si_arch);
- break;
- }
- }
- return err;
-}
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index 558e32475c35..e8ef3eb69449 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -260,65 +260,3 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __

return err;
}
-
-int
-copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from)
-{
- compat_uptr_t addr;
- compat_int_t val;
- int err;
-
- if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please be sure
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member.
- This routine must convert siginfo from 64bit to 32bit as well
- at the same time. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
- if (from->si_code < 0)
- err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
- else {
- switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_CHLD:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- case SIL_KILL:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case SIL_FAULT:
- addr = ptr_to_compat(from->si_addr);
- err |= __put_user(addr, &to->si_addr);
- break;
- case SIL_POLL:
- err |= __put_user(from->si_band, &to->si_band);
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case SIL_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- val = (compat_int_t)from->si_int;
- err |= __put_user(val, &to->si_int);
- break;
- case SIL_RT:
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_pid, &to->si_pid);
- val = (compat_int_t)from->si_int;
- err |= __put_user(val, &to->si_int);
- break;
- case SIL_SYS:
- err |= __put_user(ptr_to_compat(from->si_call_addr), &to->si_call_addr);
- err |= __put_user(from->si_syscall, &to->si_syscall);
- err |= __put_user(from->si_arch, &to->si_arch);
- break;
- }
- }
- return err;
-}
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
index d25858e4db63..a271dc0976ce 100644
--- a/arch/parisc/kernel/signal32.h
+++ b/arch/parisc/kernel/signal32.h
@@ -34,8 +34,6 @@ struct compat_ucontext {

/* ELF32 signal handling */

-int copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from);
-
/* In a deft move of uber-hackery, we decide to carry the top half of all
* 64-bit registers in a non-portable, non-ABI, hidden structure.
* Userspace can read the hidden structure if it *wants* but is never
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index 8a2363221b0c..62168e1158f1 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -119,8 +119,6 @@ typedef u32 compat_old_sigset_t;

typedef u32 compat_sigset_word;

-#define SI_PAD_SIZE32 (128/sizeof(int) - 3)
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index ee62ff7b296c..aded81169648 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -873,63 +873,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
#endif

#ifdef CONFIG_PPC64
-int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)
-{
- int err;
-
- if (!access_ok (VERIFY_WRITE, d, sizeof(*d)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please be sure
- * this code is fixed accordingly.
- * It should never copy any pad contained in the structure
- * to avoid security leaks, but must copy the generic
- * 3 ints plus the relevant union member.
- * This routine must convert siginfo from 64bit to 32bit as well
- * at the same time.
- */
- err = __put_user(s->si_signo, &d->si_signo);
- err |= __put_user(s->si_errno, &d->si_errno);
- err |= __put_user(s->si_code, &d->si_code);
- if (s->si_code < 0)
- err |= __copy_to_user(&d->_sifields._pad, &s->_sifields._pad,
- SI_PAD_SIZE32);
- else switch(siginfo_layout(s->si_signo, s->si_code)) {
- case SIL_CHLD:
- err |= __put_user(s->si_pid, &d->si_pid);
- err |= __put_user(s->si_uid, &d->si_uid);
- err |= __put_user(s->si_utime, &d->si_utime);
- err |= __put_user(s->si_stime, &d->si_stime);
- err |= __put_user(s->si_status, &d->si_status);
- break;
- case SIL_FAULT:
- err |= __put_user((unsigned int)(unsigned long)s->si_addr,
- &d->si_addr);
- break;
- case SIL_POLL:
- err |= __put_user(s->si_band, &d->si_band);
- err |= __put_user(s->si_fd, &d->si_fd);
- break;
- case SIL_TIMER:
- err |= __put_user(s->si_tid, &d->si_tid);
- err |= __put_user(s->si_overrun, &d->si_overrun);
- err |= __put_user(s->si_int, &d->si_int);
- break;
- case SIL_SYS:
- err |= __put_user(ptr_to_compat(s->si_call_addr), &d->si_call_addr);
- err |= __put_user(s->si_syscall, &d->si_syscall);
- err |= __put_user(s->si_arch, &d->si_arch);
- break;
- case SIL_RT:
- err |= __put_user(s->si_int, &d->si_int);
- /* fallthrough */
- case SIL_KILL:
- err |= __put_user(s->si_pid, &d->si_pid);
- err |= __put_user(s->si_uid, &d->si_uid);
- break;
- }
- return err;
-}

#define copy_siginfo_to_user copy_siginfo_to_user32

diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index d77ce14ffa5c..18c1eeb847b2 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -50,58 +50,6 @@ typedef struct
struct ucontext32 uc;
} rt_sigframe32;

-int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
-{
- int err;
-
- /* If you change siginfo_t structure, please be sure
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member.
- This routine must convert siginfo from 64bit to 32bit as well
- at the same time. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
- if (from->si_code < 0)
- err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
- else {
- switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_RT:
- err |= __put_user(from->si_int, &to->si_int);
- /* fallthrough */
- case SIL_KILL:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case SIL_CHLD:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- break;
- case SIL_FAULT:
- err |= __put_user((unsigned long) from->si_addr,
- &to->si_addr);
- break;
- case SIL_POLL:
- err |= __put_user(from->si_band, &to->si_band);
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case SIL_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- default:
- break;
- }
- }
- return err ? -EFAULT : 0;
-}
-
/* Store registers needed to create the signal frame */
static void store_sigregs(void)
{
diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h
index c3688ae98b90..615283e16f22 100644
--- a/arch/sparc/include/asm/compat.h
+++ b/arch/sparc/include/asm/compat.h
@@ -149,8 +149,6 @@ typedef u32 compat_old_sigset_t;

typedef u32 compat_sigset_word;

-#define SI_PAD_SIZE32 (128/sizeof(int) - 3)
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 8022bb4c65a5..44d379db3f64 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -70,59 +70,6 @@ struct rt_signal_frame32 {
/* __siginfo_rwin_t * */u32 rwin_save;
} __attribute__((aligned(8)));

-int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please be sure
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member.
- This routine must convert siginfo from 64bit to 32bit as well
- at the same time. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
- if (from->si_code < 0)
- err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
- else {
- switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case SIL_CHLD:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- default:
- case SIL_KILL:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case SIL_FAULT:
- err |= __put_user(from->si_trapno, &to->si_trapno);
- err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
- break;
- case SIL_POLL:
- err |= __put_user(from->si_band, &to->si_band);
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case SIL_RT:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- }
- }
- return err;
-}
-
/* Checks if the fp is valid. We always build signal frames which are
* 16-byte aligned, therefore we can always enforce that the restore
* frame has that property as well.
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index c6b7613256b4..769ff6ac0bf5 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -110,8 +110,6 @@ struct compat_flock64 {

typedef u32 compat_sigset_word;

-#define COMPAT_SI_PAD_SIZE (128/sizeof(int) - 3)
-
#define COMPAT_OFF_T_MAX 0x7fffffff

struct compat_ipc64_perm {
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 4e7f40a10eb3..a703bd0e0488 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -50,61 +50,6 @@ struct compat_rt_sigframe {
struct compat_ucontext uc;
};

-int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please make sure that
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
-
- if (from->si_code < 0) {
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
- } else {
- /*
- * First 32bits of unions are always present:
- * si_pid === si_band === si_tid === si_addr(LS half)
- */
- err |= __put_user(from->_sifields._pad[0],
- &to->_sifields._pad[0]);
- switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_FAULT:
- break;
- case SIL_CHLD:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- /* FALL THROUGH */
- default:
- case SIL_KILL:
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case SIL_POLL:
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case SIL_TIMER:
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case SIL_RT:
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- }
- }
- return err;
-}
-
/* The assembly shim for this function arranges to ignore the return value. */
long compat_sys_rt_sigreturn(void)
{
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 0b76fc91f672..e1c8dab86670 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -249,4 +249,8 @@ static inline bool in_compat_syscall(void)
}
#define in_compat_syscall in_compat_syscall /* override the generic impl */

+struct compat_siginfo;
+int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
+ const siginfo_t *from, bool x32_ABI);
+
#endif /* _ASM_X86_COMPAT_H */
diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h
index 4df2754ef380..44bbc39a57b3 100644
--- a/arch/x86/include/asm/fpu/signal.h
+++ b/arch/x86/include/asm/fpu/signal.h
@@ -20,12 +20,6 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
# define ia32_setup_rt_frame __setup_rt_frame
#endif

-#ifdef CONFIG_COMPAT
-int __copy_siginfo_to_user32(compat_siginfo_t __user *to,
- const siginfo_t *from, bool x32_ABI);
-#endif
-
-
extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
struct task_struct *tsk);
extern void convert_to_fxsr(struct task_struct *tsk,
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index 59148de2d83f..ac057f9b0763 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -98,6 +98,8 @@ static inline void signal_compat_build_tests(void)

void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
{
+ signal_compat_build_tests();
+
/* Don't leak in-kernel non-uapi flags to user-space */
if (oact)
oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
@@ -113,97 +115,3 @@ void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
if (in_x32_syscall())
act->sa.sa_flags |= SA_X32_ABI;
}
-
-int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
- bool x32_ABI)
-{
- int err = 0;
-
- signal_compat_build_tests();
-
- if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
- return -EFAULT;
-
- put_user_try {
- /* If you change siginfo_t structure, please make sure that
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member. */
- put_user_ex(from->si_signo, &to->si_signo);
- put_user_ex(from->si_errno, &to->si_errno);
- put_user_ex(from->si_code, &to->si_code);
-
- if (from->si_code < 0) {
- put_user_ex(from->si_pid, &to->si_pid);
- put_user_ex(from->si_uid, &to->si_uid);
- put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
- } else {
- /*
- * First 32bits of unions are always present:
- * si_pid === si_band === si_tid === si_addr(LS half)
- */
- put_user_ex(from->_sifields._pad[0],
- &to->_sifields._pad[0]);
- switch (siginfo_layout(from->si_signo, from->si_code)) {
- case SIL_FAULT:
- if (from->si_signo == SIGBUS &&
- (from->si_code == BUS_MCEERR_AR ||
- from->si_code == BUS_MCEERR_AO))
- put_user_ex(from->si_addr_lsb, &to->si_addr_lsb);
-
- if (from->si_signo == SIGSEGV) {
- if (from->si_code == SEGV_BNDERR) {
- compat_uptr_t lower = (unsigned long)from->si_lower;
- compat_uptr_t upper = (unsigned long)from->si_upper;
- put_user_ex(lower, &to->si_lower);
- put_user_ex(upper, &to->si_upper);
- }
- if (from->si_code == SEGV_PKUERR)
- put_user_ex(from->si_pkey, &to->si_pkey);
- }
- break;
- case SIL_SYS:
- put_user_ex(from->si_syscall, &to->si_syscall);
- put_user_ex(from->si_arch, &to->si_arch);
- break;
- case SIL_CHLD:
- if (!x32_ABI) {
- put_user_ex(from->si_utime, &to->si_utime);
- put_user_ex(from->si_stime, &to->si_stime);
-#ifdef CONFIG_X86_X32_ABI
- } else {
- put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
- put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
-#endif
- }
- put_user_ex(from->si_status, &to->si_status);
- /* FALL THROUGH */
- case SIL_KILL:
- put_user_ex(from->si_uid, &to->si_uid);
- break;
- case SIL_POLL:
- put_user_ex(from->si_fd, &to->si_fd);
- break;
- case SIL_TIMER:
- put_user_ex(from->si_overrun, &to->si_overrun);
- put_user_ex(ptr_to_compat(from->si_ptr),
- &to->si_ptr);
- break;
- case SIL_RT:
- put_user_ex(from->si_uid, &to->si_uid);
- put_user_ex(from->si_int, &to->si_int);
- break;
- }
- }
- } put_user_catch(err);
-
- return err;
-}
-
-/* from syscall's path, where we know the ABI */
-int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
-{
- return __copy_siginfo_to_user32(to, from, in_x32_syscall());
-}
-
diff --git a/kernel/signal.c b/kernel/signal.c
index bebe44265b8b..069edfef7828 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2815,6 +2815,96 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
}

#ifdef CONFIG_COMPAT
+int copy_siginfo_to_user32(struct compat_siginfo __user *to,
+ const struct siginfo *from)
+#ifdef CONFIG_X86_X32_ABI
+{
+ return __copy_siginfo_to_user32(to, from, in_x32_syscall());
+}
+int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
+ const struct siginfo *from, bool x32_ABI)
+#endif /* CONFIG_X86_X32_ABI */
+{
+ struct compat_siginfo new;
+ memset(&new, 0, sizeof(new));
+
+ new.si_signo = from->si_signo;
+ new.si_errno = from->si_errno;
+ new.si_code = from->si_code;
+ switch(siginfo_layout(from->si_signo, from->si_code)) {
+ case SIL_KILL:
+ new.si_pid = from->si_pid;
+ new.si_uid = from->si_uid;
+ break;
+ case SIL_TIMER:
+ new.si_tid = from->si_tid;
+ new.si_overrun = from->si_overrun;
+ new.si_int = from->si_int;
+ break;
+ case SIL_POLL:
+ new.si_band = from->si_band;
+ new.si_fd = from->si_fd;
+ break;
+ case SIL_FAULT:
+ new.si_addr = ptr_to_compat(from->si_addr);
+#ifdef __ARCH_SI_TRAPNO
+ new.si_trapno = from->si_trapno;
+#endif
+#ifdef BUS_MCEERR_AR
+ if ((from->si_signo == SIGBUS) && (from->si_code == BUS_MCEERR_AR))
+ new.si_addr_lsb = from->si_addr_lsb;
+#endif
+#ifdef BUS_MCEERR_AO
+ if ((from->si_signo == SIGBUS) && (from->si_code == BUS_MCEERR_AO))
+ new.si_addr_lsb = from->si_addr_lsb;
+#endif
+#ifdef SEGV_BNDERR
+ if ((from->si_signo == SIGSEGV) &&
+ (from->si_code == SEGV_BNDERR)) {
+ new.si_lower = ptr_to_compat(from->si_lower);
+ new.si_upper = ptr_to_compat(from->si_upper);
+ }
+#endif
+#ifdef SEGV_PKUERR
+ if ((from->si_signo == SIGSEGV) &&
+ (from->si_code == SEGV_PKUERR))
+ new.si_pkey = from->si_pkey;
+#endif
+
+ break;
+ case SIL_CHLD:
+ new.si_pid = from->si_pid;
+ new.si_uid = from->si_uid;
+ new.si_status = from->si_status;
+#ifdef CONFIG_X86_X32_ABI
+ if (x32_ABI) {
+ new._sifields._sigchld_x32._utime = from->si_utime;
+ new._sifields._sigchld_x32._stime = from->si_stime;
+ } else
+#endif
+ {
+ new.si_utime = from->si_utime;
+ new.si_stime = from->si_stime;
+ }
+ break;
+ case SIL_RT:
+ new.si_pid = from->si_pid;
+ new.si_uid = from->si_uid;
+ new.si_int = from->si_int;
+ break;
+ case SIL_SYS:
+ new.si_call_addr = ptr_to_compat(from->si_call_addr);
+ new.si_syscall = from->si_syscall;
+ new.si_arch = from->si_arch;
+ break;
+ }
+
+ if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
int copy_siginfo_from_user32(struct siginfo *to,
const struct compat_siginfo __user *ufrom)
{
--
2.14.1

2018-01-16 00:44:17

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 18/22] signal/blackfin: Move the blackfin specific si_codes to asm-generic/siginfo.h

Having si_codes in many different files simply encourages duplicate definitions
that can cause problems later. To avoid that merge the blackfin specific si_codes
into uapi/asm-generic/siginfo.h

Update copy_siginfo_to_user to copy with the absence of BUS_MCEERR_AR that blackfin
defines to be something else.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/blackfin/include/uapi/asm/siginfo.h | 32 --------------------------------
include/uapi/asm-generic/siginfo.h | 29 +++++++++++++++++++++++++++--
kernel/signal.c | 9 ++++++---
3 files changed, 33 insertions(+), 37 deletions(-)

diff --git a/arch/blackfin/include/uapi/asm/siginfo.h b/arch/blackfin/include/uapi/asm/siginfo.h
index b1db506c8d2e..8c505170f4d0 100644
--- a/arch/blackfin/include/uapi/asm/siginfo.h
+++ b/arch/blackfin/include/uapi/asm/siginfo.h
@@ -15,36 +15,4 @@

#define si_uid16 _sifields._kill._uid

-#define ILL_ILLPARAOP 2 /* illegal opcode combine ********** */
-#define ILL_ILLEXCPT 4 /* unrecoverable exception ********** */
-#define ILL_CPLB_VI 9 /* D/I CPLB protect violation ******** */
-#define ILL_CPLB_MISS 10 /* D/I CPLB miss ******** */
-#define ILL_CPLB_MULHIT 11 /* D/I CPLB multiple hit ******** */
-#undef NSIGILL
-#define NSIGILL 11
-
-/*
- * SIGBUS si_codes
- */
-#define BUS_OPFETCH 4 /* error from instruction fetch ******** */
-#undef NSIGBUS
-#define NSIGBUS 4
-
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_STEP 1 /* single-step breakpoint************* */
-#define TRAP_TRACEFLOW 2 /* trace buffer overflow ************* */
-#define TRAP_WATCHPT 3 /* watchpoint match ************* */
-#define TRAP_ILLTRAP 4 /* illegal trap ************* */
-#undef NSIGTRAP
-#define NSIGTRAP 4
-
-/*
- * SIGSEGV si_codes
- */
-#define SEGV_STACKFLOW 3 /* stack overflow */
-#undef NSIGSEGV
-#define NSIGSEGV 3
-
#endif /* _UAPI_BFIN_SIGINFO_H */
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 7a268db1c44f..254afc31e3be 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -179,13 +179,24 @@ typedef struct siginfo {
* SIGILL si_codes
*/
#define ILL_ILLOPC 1 /* illegal opcode */
+#ifdef __bfin__
+# define ILL_ILLPARAOP 2 /* illegal opcode combine */
+#endif
#define ILL_ILLOPN 2 /* illegal operand */
#define ILL_ILLADR 3 /* illegal addressing mode */
#define ILL_ILLTRP 4 /* illegal trap */
+#ifdef __bfin__
+# define ILL_ILLEXCPT 4 /* unrecoverable exception */
+#endif
#define ILL_PRVOPC 5 /* privileged opcode */
#define ILL_PRVREG 6 /* privileged register */
#define ILL_COPROC 7 /* coprocessor error */
#define ILL_BADSTK 8 /* internal stack error */
+#ifdef __bfin__
+# define ILL_CPLB_VI 9 /* D/I CPLB protect violation */
+# define ILL_CPLB_MISS 10 /* D/I CPLB miss */
+# define ILL_CPLB_MULHIT 11 /* D/I CPLB multiple hit */
+#endif
#ifdef __tile__
# define ILL_DBLFLT 9 /* double fault */
# define ILL_HARDWALL 10 /* user networks hardwall violation */
@@ -225,7 +236,11 @@ typedef struct siginfo {
*/
#define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
-#define SEGV_BNDERR 3 /* failed address bound checks */
+#ifdef __bfin__
+# define SEGV_STACKFLOW 3 /* stack overflow */
+#else
+# define SEGV_BNDERR 3 /* failed address bound checks */
+#endif
#ifdef __ia64__
# define __SEGV_PSTKOVF 4 /* paragraph stack overflow */
#else
@@ -239,8 +254,12 @@ typedef struct siginfo {
#define BUS_ADRALN 1 /* invalid address alignment */
#define BUS_ADRERR 2 /* non-existent physical address */
#define BUS_OBJERR 3 /* object specific hardware error */
+#ifdef __bfin__
+# define BUS_OPFETCH 4 /* error from instruction fetch */
+#else
/* hardware memory error consumed on a machine check: action required */
-#define BUS_MCEERR_AR 4
+# define BUS_MCEERR_AR 4
+#endif
/* hardware memory error detected in process but not consumed: action optional*/
#define BUS_MCEERR_AO 5
#define NSIGBUS 5
@@ -252,6 +271,12 @@ typedef struct siginfo {
#define TRAP_TRACE 2 /* process trace trap */
#define TRAP_BRANCH 3 /* process taken branch trap */
#define TRAP_HWBKPT 4 /* hardware breakpoint/watchpoint */
+#ifdef __bfin__
+# define TRAP_STEP 1 /* single-step breakpoint */
+# define TRAP_TRACEFLOW 2 /* trace buffer overflow */
+# define TRAP_WATCHPT 3 /* watchpoint match */
+# define TRAP_ILLTRAP 4 /* illegal trap */
+#endif
#define NSIGTRAP 4

/*
diff --git a/kernel/signal.c b/kernel/signal.c
index 47c87b1d0b8a..4c3f4448c5f1 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2770,13 +2770,16 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
err |= __put_user(from->si_flags, &to->si_flags);
err |= __put_user(from->si_isr, &to->si_isr);
#endif
-#ifdef BUS_MCEERR_AO
/*
* Other callers might not initialize the si_lsb field,
* so check explicitly for the right codes here.
*/
- if (from->si_signo == SIGBUS &&
- (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
+#ifdef BUS_MCEERR_AR
+ if (from->si_signo == SIGBUS && from->si_code == BUS_MCEERR_AR)
+ err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
+#endif
+#ifdef BUS_MCEERR_AO
+ if (from->si_signo == SIGBUS && from->si_code == BUS_MCEERR_AO)
err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
#endif
#ifdef SEGV_BNDERR
--
2.14.1

2018-01-16 00:44:20

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 11/22] signal: kill __ARCH_SI_UID_T

From: Al Viro <[email protected]>

it's always __kernel_uid32_t

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
include/uapi/asm-generic/siginfo.h | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index a650d252de0a..d32f62a7f95c 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -23,10 +23,6 @@ typedef union sigval {
#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int))
#endif

-#ifndef __ARCH_SI_UID_T
-#define __ARCH_SI_UID_T __kernel_uid32_t
-#endif
-
/*
* The default "si_band" type is "long", as specified by POSIX.
* However, some architectures want to override this to "int"
@@ -60,14 +56,13 @@ typedef struct siginfo {
/* kill() */
struct {
__kernel_pid_t _pid; /* sender's pid */
- __ARCH_SI_UID_T _uid; /* sender's uid */
+ __kernel_uid32_t _uid; /* sender's uid */
} _kill;

/* POSIX.1b timers */
struct {
__kernel_timer_t _tid; /* timer id */
int _overrun; /* overrun count */
- char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
sigval_t _sigval; /* same as below */
int _sys_private; /* not to be passed to user */
} _timer;
@@ -75,14 +70,14 @@ typedef struct siginfo {
/* POSIX.1b signals */
struct {
__kernel_pid_t _pid; /* sender's pid */
- __ARCH_SI_UID_T _uid; /* sender's uid */
+ __kernel_uid32_t _uid; /* sender's uid */
sigval_t _sigval;
} _rt;

/* SIGCHLD */
struct {
__kernel_pid_t _pid; /* which child */
- __ARCH_SI_UID_T _uid; /* sender's uid */
+ __kernel_uid32_t _uid; /* sender's uid */
int _status; /* exit code */
__ARCH_SI_CLOCK_T _utime;
__ARCH_SI_CLOCK_T _stime;
--
2.14.1

2018-01-16 00:44:15

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 12/22] signal: unify compat_siginfo_t

From: Al Viro <[email protected]>

--EWB Added #ifdef CONFIG_X86_X32_ABI to arch/x86/kernel/signal_compat.c
Changed #ifdef CONFIG_X86_X32 to #ifdef CONFIG_X86_X32_ABI in
linux/compat.h

CONFIG_X86_X32 is set when the user requests X32 support.

CONFIG_X86_X32_ABI is set when the user requests X32 support
and the tool-chain has X32 allowing X32 support to be built.

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
arch/arm64/include/asm/compat.h | 63 ---------------------------
arch/mips/include/asm/compat.h | 71 ------------------------------
arch/parisc/include/asm/compat.h | 63 ---------------------------
arch/powerpc/include/asm/compat.h | 62 ---------------------------
arch/s390/include/asm/compat.h | 72 -------------------------------
arch/sparc/include/asm/compat.h | 56 ------------------------
arch/tile/include/asm/compat.h | 58 -------------------------
arch/x86/include/asm/compat.h | 80 ----------------------------------
arch/x86/kernel/signal_compat.c | 4 ++
include/linux/compat.h | 90 +++++++++++++++++++++++++++++++++++++++
10 files changed, 94 insertions(+), 525 deletions(-)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index dd32fe19ec58..c00c62e1a4a3 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -150,69 +150,6 @@ typedef u32 compat_old_sigset_t;

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
-typedef struct compat_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[128/sizeof(int) - 3];
-
- /* kill() */
- struct {
- compat_pid_t _pid; /* sender's pid */
- __compat_uid32_t _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- compat_pid_t _pid; /* sender's pid */
- __compat_uid32_t _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- compat_pid_t _pid; /* which child */
- __compat_uid32_t _uid; /* sender's uid */
- int _status; /* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- compat_uptr_t _addr; /* faulting insn/memory ref. */
- short _addr_lsb; /* LSB of the reported address */
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
-
- /* SIGSYS */
- struct {
- compat_uptr_t _call_addr; /* calling user insn */
- int _syscall; /* triggering system call number */
- compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */
- } _sigsys;
- } _sifields;
-} compat_siginfo_t;
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
index 49691331ada4..fe7d445f675f 100644
--- a/arch/mips/include/asm/compat.h
+++ b/arch/mips/include/asm/compat.h
@@ -126,79 +126,8 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
-/* Can't use the generic version because si_code and si_errno are swapped */
-
#define SI_PAD_SIZE32 (128/sizeof(int) - 3)

-typedef struct compat_siginfo {
- int si_signo;
- int si_code;
- int si_errno;
-
- union {
- int _pad[128 / sizeof(int) - 3];
-
- /* kill() */
- struct {
- compat_pid_t _pid; /* sender's pid */
- __compat_uid32_t _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- compat_pid_t _pid; /* sender's pid */
- __compat_uid32_t _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- compat_pid_t _pid; /* which child */
- __compat_uid32_t _uid; /* sender's uid */
- int _status; /* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- compat_uptr_t _addr; /* faulting insn/memory ref. */
-#ifdef __ARCH_SI_TRAPNO
- int _trapno; /* TRAP # which caused the signal */
-#endif
- short _addr_lsb; /* LSB of the reported address */
- struct {
- compat_uptr_t _lower;
- compat_uptr_t _upper;
- } _addr_bnd;
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
-
- struct {
- compat_uptr_t _call_addr; /* calling insn */
- int _syscall; /* triggering system call number */
- compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */
- } _sigsys;
- } _sifields;
-} compat_siginfo_t;
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h
index cf3bcacec027..c22db5323244 100644
--- a/arch/parisc/include/asm/compat.h
+++ b/arch/parisc/include/asm/compat.h
@@ -130,69 +130,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
-typedef struct compat_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[128/sizeof(int) - 3];
-
- /* kill() */
- struct {
- unsigned int _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- char _pad[sizeof(unsigned int) - sizeof(int)];
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- unsigned int _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- unsigned int _pid; /* which child */
- unsigned int _uid; /* sender's uid */
- int _status; /* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- unsigned int _addr; /* faulting insn/memory ref. */
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
-
- /* SIGSYS */
- struct {
- compat_uptr_t _call_addr; /* calling user insn */
- int _syscall; /* triggering system call number */
- compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */
- } _sigsys;
- } _sifields;
-} compat_siginfo_t;
-
#define COMPAT_OFF_T_MAX 0x7fffffff

struct compat_ipc64_perm {
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index e02de2fd56e3..8a2363221b0c 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -119,70 +119,8 @@ typedef u32 compat_old_sigset_t;

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
#define SI_PAD_SIZE32 (128/sizeof(int) - 3)

-typedef struct compat_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[SI_PAD_SIZE32];
-
- /* kill() */
- struct {
- compat_pid_t _pid; /* sender's pid */
- __compat_uid_t _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- compat_pid_t _pid; /* sender's pid */
- __compat_uid_t _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- compat_pid_t _pid; /* which child */
- __compat_uid_t _uid; /* sender's uid */
- int _status; /* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
- struct {
- unsigned int _addr; /* faulting insn/memory ref. */
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
-
- /* SIGSYS */
- struct {
- unsigned int _call_addr; /* calling insn */
- int _syscall; /* triggering system call number */
- unsigned int _arch; /* AUDIT_ARCH_* of syscall */
- } _sigsys;
- } _sifields;
-} compat_siginfo_t;
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index 3a187c4932a5..9830fb6b076e 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -189,78 +189,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
-typedef struct compat_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[128/sizeof(int) - 3];
-
- /* kill() */
- struct {
- pid_t _pid; /* sender's pid */
- uid_t _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- pid_t _pid; /* sender's pid */
- uid_t _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- pid_t _pid; /* which child */
- uid_t _uid; /* sender's uid */
- int _status;/* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- __u32 _addr; /* faulting insn/memory ref. - pointer */
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
- } _sifields;
-} compat_siginfo_t;
-
-/*
- * How these fields are to be accessed.
- */
-#define si_pid _sifields._kill._pid
-#define si_uid _sifields._kill._uid
-#define si_status _sifields._sigchld._status
-#define si_utime _sifields._sigchld._utime
-#define si_stime _sifields._sigchld._stime
-#define si_value _sifields._rt._sigval
-#define si_int _sifields._rt._sigval.sival_int
-#define si_ptr _sifields._rt._sigval.sival_ptr
-#define si_addr _sifields._sigfault._addr
-#define si_band _sifields._sigpoll._band
-#define si_fd _sifields._sigpoll._fd
-#define si_tid _sifields._timer._tid
-#define si_overrun _sifields._timer._overrun
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h
index 2d9f4fd5f74a..c3688ae98b90 100644
--- a/arch/sparc/include/asm/compat.h
+++ b/arch/sparc/include/asm/compat.h
@@ -149,64 +149,8 @@ typedef u32 compat_old_sigset_t;

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
#define SI_PAD_SIZE32 (128/sizeof(int) - 3)

-typedef struct compat_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[SI_PAD_SIZE32];
-
- /* kill() */
- struct {
- compat_pid_t _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- compat_pid_t _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- compat_pid_t _pid; /* which child */
- unsigned int _uid; /* sender's uid */
- int _status; /* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
- struct {
- u32 _addr; /* faulting insn/memory ref. */
- int _trapno;
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
- } _sifields;
-} compat_siginfo_t;
-
#define COMPAT_OFF_T_MAX 0x7fffffff

/*
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index 59ab9fa784b3..c6b7613256b4 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -110,66 +110,8 @@ struct compat_flock64 {

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
#define COMPAT_SI_PAD_SIZE (128/sizeof(int) - 3)

-typedef struct compat_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[COMPAT_SI_PAD_SIZE];
-
- /* kill() */
- struct {
- unsigned int _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- unsigned int _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- unsigned int _pid; /* which child */
- unsigned int _uid; /* sender's uid */
- int _status; /* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- unsigned int _addr; /* faulting insn/memory ref. */
-#ifdef __ARCH_SI_TRAPNO
- int _trapno; /* TRAP # which caused the signal */
-#endif
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
- } _sifields;
-} compat_siginfo_t;
-
#define COMPAT_OFF_T_MAX 0x7fffffff

struct compat_ipc64_perm {
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 1b6886a78562..0b76fc91f672 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -127,86 +127,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */

typedef u32 compat_sigset_word;

-typedef union compat_sigval {
- compat_int_t sival_int;
- compat_uptr_t sival_ptr;
-} compat_sigval_t;
-
-typedef struct compat_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[128/sizeof(int) - 3];
-
- /* kill() */
- struct {
- unsigned int _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- compat_timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval; /* same as below */
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- unsigned int _pid; /* sender's pid */
- unsigned int _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- unsigned int _pid; /* which child */
- unsigned int _uid; /* sender's uid */
- int _status; /* exit code */
- compat_clock_t _utime;
- compat_clock_t _stime;
- } _sigchld;
-
- /* SIGCHLD (x32 version) */
- struct {
- unsigned int _pid; /* which child */
- unsigned int _uid; /* sender's uid */
- int _status; /* exit code */
- compat_s64 _utime;
- compat_s64 _stime;
- } _sigchld_x32;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- unsigned int _addr; /* faulting insn/memory ref. */
- short int _addr_lsb; /* Valid LSB of the reported address. */
- union {
- /* used when si_code=SEGV_BNDERR */
- struct {
- compat_uptr_t _lower;
- compat_uptr_t _upper;
- } _addr_bnd;
- /* used when si_code=SEGV_PKUERR */
- compat_u32 _pkey;
- };
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
-
- struct {
- unsigned int _call_addr; /* calling insn */
- int _syscall; /* triggering system call number */
- unsigned int _arch; /* AUDIT_ARCH_* of syscall */
- } _sigsys;
- } _sifields;
-} compat_siginfo_t;
-
#define COMPAT_OFF_T_MAX 0x7fffffff

struct compat_ipc64_perm {
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index 85425ea30661..27495909932d 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -75,9 +75,11 @@ static inline void signal_compat_build_tests(void)
CHECK_CSI_SIZE (_sigchld, 5*sizeof(int));
CHECK_SI_SIZE (_sigchld, 8*sizeof(int));

+#ifdef CONFIG_X86_X32_ABI
CHECK_CSI_OFFSET(_sigchld_x32);
CHECK_CSI_SIZE (_sigchld_x32, 7*sizeof(int));
/* no _sigchld_x32 in the generic siginfo_t */
+#endif

CHECK_CSI_OFFSET(_sigfault);
CHECK_CSI_SIZE (_sigfault, 4*sizeof(int));
@@ -169,9 +171,11 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
if (!x32_ABI) {
put_user_ex(from->si_utime, &to->si_utime);
put_user_ex(from->si_stime, &to->si_stime);
+#ifdef CONFIG_X86_X32_ABI
} else {
put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
+#endif
}
put_user_ex(from->si_status, &to->si_status);
/* FALL THROUGH */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 0fc36406f32c..8f8e3ef247de 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -157,6 +157,96 @@ struct compat_sigaction {
compat_sigset_t sa_mask __packed;
};

+typedef union compat_sigval {
+ compat_int_t sival_int;
+ 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
+
+ union {
+ int _pad[128/sizeof(int) - 3];
+
+ /* kill() */
+ struct {
+ compat_pid_t _pid; /* sender's pid */
+ __compat_uid32_t _uid; /* sender's uid */
+ } _kill;
+
+ /* POSIX.1b timers */
+ struct {
+ compat_timer_t _tid; /* timer id */
+ int _overrun; /* overrun count */
+ compat_sigval_t _sigval; /* same as below */
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ compat_pid_t _pid; /* sender's pid */
+ __compat_uid32_t _uid; /* sender's uid */
+ compat_sigval_t _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct {
+ compat_pid_t _pid; /* which child */
+ __compat_uid32_t _uid; /* sender's uid */
+ int _status; /* exit code */
+ compat_clock_t _utime;
+ compat_clock_t _stime;
+ } _sigchld;
+
+#ifdef CONFIG_X86_X32_ABI
+ /* SIGCHLD (x32 version) */
+ struct {
+ compat_pid_t _pid; /* which child */
+ __compat_uid32_t _uid; /* sender's uid */
+ int _status; /* exit code */
+ compat_s64 _utime;
+ compat_s64 _stime;
+ } _sigchld_x32;
+#endif
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */
+ struct {
+ compat_uptr_t _addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_TRAPNO
+ int _trapno; /* TRAP # which caused the signal */
+#endif
+ short int _addr_lsb; /* Valid LSB of the reported address. */
+ union {
+ /* used when si_code=SEGV_BNDERR */
+ struct {
+ compat_uptr_t _lower;
+ compat_uptr_t _upper;
+ } _addr_bnd;
+ /* used when si_code=SEGV_PKUERR */
+ u32 _pkey;
+ };
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct {
+ compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ int _fd;
+ } _sigpoll;
+
+ struct {
+ 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;
+
/*
* These functions operate on 32- or 64-bit specs depending on
* COMPAT_USE_64BIT_TIME, hence the void user pointer arguments.
--
2.14.1

2018-01-16 00:44:13

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 17/22] signal/tile: Move the tile specific si_codes to asm-generic/siginfo.h

Having si_codes in many different files simply encourages duplicate definitions
that can cause problems later. To avoid that merge the tile specific si_codes
into uapi/asm-generic/siginfo.h

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/tile/include/uapi/asm/siginfo.h | 8 --------
include/uapi/asm-generic/siginfo.h | 4 ++++
2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/arch/tile/include/uapi/asm/siginfo.h b/arch/tile/include/uapi/asm/siginfo.h
index f234d24fff55..a812fcbf4267 100644
--- a/arch/tile/include/uapi/asm/siginfo.h
+++ b/arch/tile/include/uapi/asm/siginfo.h
@@ -24,12 +24,4 @@

#include <asm-generic/siginfo.h>

-/*
- * Additional Tile-specific SIGILL si_codes
- */
-#define ILL_DBLFLT 9 /* double fault */
-#define ILL_HARDWALL 10 /* user networks hardwall violation */
-#undef NSIGILL
-#define NSIGILL 10
-
#endif /* _ASM_TILE_SIGINFO_H */
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index f1c0af4f36a4..7a268db1c44f 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -186,6 +186,10 @@ typedef struct siginfo {
#define ILL_PRVREG 6 /* privileged register */
#define ILL_COPROC 7 /* coprocessor error */
#define ILL_BADSTK 8 /* internal stack error */
+#ifdef __tile__
+# define ILL_DBLFLT 9 /* double fault */
+# define ILL_HARDWALL 10 /* user networks hardwall violation */
+#endif
#ifdef __ia64__
# define ILL_BADIADDR 9 /* unimplemented instruction address */
# define __ILL_BREAK 10 /* illegal break */
--
2.14.1

2018-01-16 00:43:40

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 16/22] signal/frv: Move the frv specific si_codes to asm-generic/siginfo.h

Having si_codes in many different files simply encourages duplicate definitions
that can cause problems later. To avoid that merce the frv specific si_codes
into uapi/asm-generic/siginfo.h

This allows the removal of arch/frv/uapi/include/asm/siginfo.h as the last
last meaningful definition it held was FPE_MDAOVF.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/frv/include/uapi/asm/Kbuild | 1 +
arch/frv/include/uapi/asm/siginfo.h | 13 -------------
include/uapi/asm-generic/siginfo.h | 3 +++
3 files changed, 4 insertions(+), 13 deletions(-)
delete mode 100644 arch/frv/include/uapi/asm/siginfo.h

diff --git a/arch/frv/include/uapi/asm/Kbuild b/arch/frv/include/uapi/asm/Kbuild
index 14a2e9af97e9..5354b0f84d41 100644
--- a/arch/frv/include/uapi/asm/Kbuild
+++ b/arch/frv/include/uapi/asm/Kbuild
@@ -1,4 +1,5 @@
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm

+generic-y += siginfo.h
generic-y += bpf_perf_event.h
diff --git a/arch/frv/include/uapi/asm/siginfo.h b/arch/frv/include/uapi/asm/siginfo.h
deleted file mode 100644
index 4c8c975747ac..000000000000
--- a/arch/frv/include/uapi/asm/siginfo.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _ASM_SIGINFO_H
-#define _ASM_SIGINFO_H
-
-#include <linux/types.h>
-#include <asm-generic/siginfo.h>
-
-#define FPE_MDAOVF 9 /* media overflow */
-#undef NSIGFPE
-#define NSIGFPE 9
-
-#endif
-
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 2f0ae4607603..f1c0af4f36a4 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -204,6 +204,9 @@ typedef struct siginfo {
#define FPE_FLTRES 6 /* floating point inexact result */
#define FPE_FLTINV 7 /* floating point invalid operation */
#define FPE_FLTSUB 8 /* subscript out of range */
+#ifdef __frv__
+# define FPE_MDAOVF 9 /* media overflow */
+#endif
#ifdef __ia64__
# define __FPE_DECOVF 9 /* decimal overflow */
# define __FPE_DECDIV 10 /* decimal division by zero */
--
2.14.1

2018-01-16 00:45:13

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 20/22] signal: Unify and correct copy_siginfo_from_user32

The function copy_siginfo_from_user32 is used for two things, in ptrace
since the dawn of siginfo for arbirarily modifying a signal that
user space sees, and in sigqueueinfo to send a signal with arbirary
siginfo data.

Create a single copy of copy_siginfo_from_user32 that all architectures
share, and teach it to handle all of the cases in the siginfo union.

In the generic version of copy_siginfo_from_user32 ensure that all
of the fields in siginfo are initialized so that the siginfo structure
can be safely copied to userspace if necessary.

When copying the embedded sigval union copy the si_int member. That
ensures the 32bit values passes through the kernel unchanged.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arm64/kernel/signal32.c | 10 -----
arch/mips/kernel/signal32.c | 10 -----
arch/parisc/kernel/signal32.c | 44 ----------------------
arch/parisc/kernel/signal32.h | 1 -
arch/powerpc/kernel/signal_32.c | 9 -----
arch/s390/kernel/compat_signal.c | 48 ------------------------
arch/sparc/kernel/signal32.c | 16 --------
arch/tile/kernel/compat_signal.c | 18 ---------
arch/x86/kernel/signal_compat.c | 21 -----------
include/linux/compat.h | 2 +-
kernel/signal.c | 81 ++++++++++++++++++++++++++++++++++++++++
11 files changed, 82 insertions(+), 178 deletions(-)

diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 22711ee8e36c..4377907dbb70 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -195,16 +195,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
return err;
}

-int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
-{
- if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
- copy_from_user(to->_sifields._pad,
- from->_sifields._pad, SI_PAD_SIZE))
- return -EFAULT;
-
- return 0;
-}
-
/*
* VFP save/restore code.
*
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index cf5c7c05e5a3..500b5e4634ea 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -133,13 +133,3 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
}
return err;
}
-
-int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
-{
- if (copy_from_user(to, from, 3*sizeof(int)) ||
- copy_from_user(to->_sifields._pad,
- from->_sifields._pad, SI_PAD_SIZE32))
- return -EFAULT;
-
- return 0;
-}
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index 41afa9cd1f55..558e32475c35 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -261,50 +261,6 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __
return err;
}

-int
-copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
-{
- compat_uptr_t addr;
- int err;
-
- if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
- return -EFAULT;
-
- err = __get_user(to->si_signo, &from->si_signo);
- err |= __get_user(to->si_errno, &from->si_errno);
- err |= __get_user(to->si_code, &from->si_code);
-
- if (to->si_code < 0)
- err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
- else {
- switch (siginfo_layout(to->si_signo, to->si_code)) {
- case SIL_CHLD:
- err |= __get_user(to->si_utime, &from->si_utime);
- err |= __get_user(to->si_stime, &from->si_stime);
- err |= __get_user(to->si_status, &from->si_status);
- default:
- case SIL_KILL:
- err |= __get_user(to->si_pid, &from->si_pid);
- err |= __get_user(to->si_uid, &from->si_uid);
- break;
- case SIL_FAULT:
- err |= __get_user(addr, &from->si_addr);
- to->si_addr = compat_ptr(addr);
- break;
- case SIL_POLL:
- err |= __get_user(to->si_band, &from->si_band);
- err |= __get_user(to->si_fd, &from->si_fd);
- break;
- case SIL_RT:
- err |= __get_user(to->si_pid, &from->si_pid);
- err |= __get_user(to->si_uid, &from->si_uid);
- err |= __get_user(to->si_int, &from->si_int);
- break;
- }
- }
- return err;
-}
-
int
copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from)
{
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
index 719e7417732c..d25858e4db63 100644
--- a/arch/parisc/kernel/signal32.h
+++ b/arch/parisc/kernel/signal32.h
@@ -35,7 +35,6 @@ struct compat_ucontext {
/* ELF32 signal handling */

int copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from);
-int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from);

/* In a deft move of uber-hackery, we decide to carry the top half of all
* 64-bit registers in a non-portable, non-ABI, hidden structure.
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 9ffd73296f64..ee62ff7b296c 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -933,15 +933,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)

#define copy_siginfo_to_user copy_siginfo_to_user32

-int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
-{
- if (copy_from_user(to, from, 3*sizeof(int)) ||
- copy_from_user(to->_sifields._pad,
- from->_sifields._pad, SI_PAD_SIZE32))
- return -EFAULT;
-
- return 0;
-}
#endif /* CONFIG_PPC64 */

/*
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index ef246940b44c..d77ce14ffa5c 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -102,54 +102,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
return err ? -EFAULT : 0;
}

-int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
-{
- int err;
- u32 tmp;
-
- err = __get_user(to->si_signo, &from->si_signo);
- err |= __get_user(to->si_errno, &from->si_errno);
- err |= __get_user(to->si_code, &from->si_code);
-
- if (to->si_code < 0)
- err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
- else {
- switch (siginfo_layout(to->si_signo, to->si_code)) {
- case SIL_RT:
- err |= __get_user(to->si_int, &from->si_int);
- /* fallthrough */
- case SIL_KILL:
- err |= __get_user(to->si_pid, &from->si_pid);
- err |= __get_user(to->si_uid, &from->si_uid);
- break;
- case SIL_CHLD:
- err |= __get_user(to->si_pid, &from->si_pid);
- err |= __get_user(to->si_uid, &from->si_uid);
- err |= __get_user(to->si_utime, &from->si_utime);
- err |= __get_user(to->si_stime, &from->si_stime);
- err |= __get_user(to->si_status, &from->si_status);
- break;
- case SIL_FAULT:
- err |= __get_user(tmp, &from->si_addr);
- to->si_addr = (void __force __user *)
- (u64) (tmp & PSW32_ADDR_INSN);
- break;
- case SIL_POLL:
- err |= __get_user(to->si_band, &from->si_band);
- err |= __get_user(to->si_fd, &from->si_fd);
- break;
- case SIL_TIMER:
- err |= __get_user(to->si_tid, &from->si_tid);
- err |= __get_user(to->si_overrun, &from->si_overrun);
- err |= __get_user(to->si_int, &from->si_int);
- break;
- default:
- break;
- }
- }
- return err ? -EFAULT : 0;
-}
-
/* Store registers needed to create the signal frame */
static void store_sigregs(void)
{
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 54a6159b9cd8..8022bb4c65a5 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -123,22 +123,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
return err;
}

-/* CAUTION: This is just a very minimalist implementation for the
- * sake of compat_sys_rt_sigqueueinfo()
- */
-int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
-{
- if (!access_ok(VERIFY_WRITE, from, sizeof(compat_siginfo_t)))
- return -EFAULT;
-
- if (copy_from_user(to, from, 3*sizeof(int)) ||
- copy_from_user(to->_sifields._pad, from->_sifields._pad,
- SI_PAD_SIZE))
- return -EFAULT;
-
- return 0;
-}
-
/* Checks if the fp is valid. We always build signal frames which are
* 16-byte aligned, therefore we can always enforce that the restore
* frame has that property as well.
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 971d87a1d8cf..4e7f40a10eb3 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -105,24 +105,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
return err;
}

-int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
-{
- int err;
-
- if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
- return -EFAULT;
-
- err = __get_user(to->si_signo, &from->si_signo);
- err |= __get_user(to->si_errno, &from->si_errno);
- err |= __get_user(to->si_code, &from->si_code);
-
- err |= __get_user(to->si_pid, &from->si_pid);
- err |= __get_user(to->si_uid, &from->si_uid);
- err |= __get_user(to->si_int, &from->si_int);
-
- return err;
-}
-
/* The assembly shim for this function arranges to ignore the return value. */
long compat_sys_rt_sigreturn(void)
{
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index feb3ac135d0c..59148de2d83f 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -207,24 +207,3 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
return __copy_siginfo_to_user32(to, from, in_x32_syscall());
}

-int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
-{
- int err = 0;
- u32 ptr32;
-
- if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
- return -EFAULT;
-
- get_user_try {
- get_user_ex(to->si_signo, &from->si_signo);
- get_user_ex(to->si_errno, &from->si_errno);
- get_user_ex(to->si_code, &from->si_code);
-
- get_user_ex(to->si_pid, &from->si_pid);
- get_user_ex(to->si_uid, &from->si_uid);
- get_user_ex(ptr32, &from->si_ptr);
- to->si_ptr = compat_ptr(ptr32);
- } get_user_catch(err);
-
- return err;
-}
diff --git a/include/linux/compat.h b/include/linux/compat.h
index e698ec1908d9..8a9643857c4a 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -510,7 +510,7 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size);
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
unsigned long bitmap_size);
-int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from);
+int copy_siginfo_from_user32(siginfo_t *to, const struct compat_siginfo __user *from);
int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from);
int get_compat_sigevent(struct sigevent *event,
const struct compat_sigevent __user *u_event);
diff --git a/kernel/signal.c b/kernel/signal.c
index 4c3f4448c5f1..5211b1b57163 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2814,6 +2814,87 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
return err;
}

+#ifdef CONFIG_COMPAT
+int copy_siginfo_from_user32(struct siginfo *to,
+ const struct compat_siginfo __user *ufrom)
+{
+ struct compat_siginfo from;
+
+ if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
+ return -EFAULT;
+
+ clear_siginfo(to);
+ to->si_signo = from.si_signo;
+ to->si_errno = from.si_errno;
+ to->si_code = from.si_code;
+ switch(siginfo_layout(from.si_signo, from.si_code)) {
+ case SIL_KILL:
+ to->si_pid = from.si_pid;
+ to->si_uid = from.si_uid;
+ break;
+ case SIL_TIMER:
+ to->si_tid = from.si_tid;
+ to->si_overrun = from.si_overrun;
+ to->si_int = from.si_int;
+ break;
+ case SIL_POLL:
+ to->si_band = from.si_band;
+ to->si_fd = from.si_fd;
+ break;
+ case SIL_FAULT:
+ to->si_addr = compat_ptr(from.si_addr);
+#ifdef __ARCH_SI_TRAPNO
+ to->si_trapno = from.si_trapno;
+#endif
+#ifdef BUS_MCEERR_AR
+ if ((from.si_signo == SIGBUS) && (from.si_code == BUS_MCEERR_AR))
+ to->si_addr_lsb = from.si_addr_lsb;
+#endif
+#ifdef BUS_MCEER_AO
+ if ((from.si_signo == SIGBUS) && (from.si_code == BUS_MCEERR_AO))
+ to->si_addr_lsb = from.si_addr_lsb;
+#endif
+#ifdef SEGV_BNDERR
+ if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_BNDERR)) {
+ to->si_lower = compat_ptr(from.si_lower);
+ to->si_upper = compat_ptr(from.si_upper);
+ }
+#endif
+#ifdef SEGV_PKUERR
+ if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_PKUERR))
+ to->si_pkey = from.si_pkey;
+#endif
+ break;
+ case SIL_CHLD:
+ to->si_pid = from.si_pid;
+ to->si_uid = from.si_uid;
+ to->si_status = from.si_status;
+#ifdef CONFIG_X86_X32_ABI
+ if (in_x32_syscall()) {
+ to->si_utime = from._sifields._sigchld_x32._utime;
+ to->si_stime = from._sifields._sigchld_x32._stime;
+ } else
+#endif
+ {
+ to->si_utime = from.si_utime;
+ to->si_stime = from.si_stime;
+ }
+ break;
+ case SIL_RT:
+ to->si_pid = from.si_pid;
+ to->si_uid = from.si_uid;
+ to->si_int = from.si_int;
+ break;
+ case SIL_SYS:
+ to->si_call_addr = compat_ptr(from.si_call_addr);
+ to->si_syscall = from.si_syscall;
+ to->si_arch = from.si_arch;
+ break;
+ }
+ return 0;
+}
+#endif /* CONFIG_COMPAT */
+
/**
* do_sigtimedwait - wait for queued signals specified in @which
* @which: queued signals to wait for
--
2.14.1

2018-01-16 00:45:33

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity

The addr_lsb fields is only valid and available when the
signal is SIGBUS and the si_code is BUS_MCEERR_AR or BUS_MCEERR_AO.
Document this with a comment and place the field in the _sigfault union
to make this clear.

All of the fields stay in the same physical location so both the old
and new definitions of struct siginfo will continue to work.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/linux/compat.h | 12 ++++++++++--
include/uapi/asm-generic/siginfo.h | 14 +++++++++++---
2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/include/linux/compat.h b/include/linux/compat.h
index 8f8e3ef247de..e698ec1908d9 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -221,15 +221,23 @@ typedef struct compat_siginfo {
#ifdef __ARCH_SI_TRAPNO
int _trapno; /* TRAP # which caused the signal */
#endif
- short int _addr_lsb; /* Valid LSB of the reported address. */
union {
+ /*
+ * used when si_code=BUS_MCEERR_AR or
+ * used when si_code=BUS_MCEERR_AO
+ */
+ short int _addr_lsb; /* Valid LSB of the reported address. */
/* used when si_code=SEGV_BNDERR */
struct {
+ short _dummy_bnd;
compat_uptr_t _lower;
compat_uptr_t _upper;
} _addr_bnd;
/* used when si_code=SEGV_PKUERR */
- u32 _pkey;
+ struct {
+ short _dummy_pkey;
+ u32 _pkey;
+ } _addr_pkey;
};
} _sigfault;

diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index d32f62a7f95c..eef4d778a5d4 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -94,15 +94,23 @@ typedef struct siginfo {
unsigned int _flags; /* see ia64 si_flags */
unsigned long _isr; /* isr */
#endif
- short _addr_lsb; /* LSB of the reported address */
union {
+ /*
+ * used when si_code=BUS_MCEERR_AR or
+ * used when si_code=BUS_MCEERR_AO
+ */
+ short _addr_lsb; /* LSB of the reported address */
/* used when si_code=SEGV_BNDERR */
struct {
+ short _dummy_bnd;
void __user *_lower;
void __user *_upper;
} _addr_bnd;
/* used when si_code=SEGV_PKUERR */
- __u32 _pkey;
+ struct {
+ short _dummy_pkey;
+ __u32 _pkey;
+ } _addr_pkey;
};
} _sigfault;

@@ -142,7 +150,7 @@ typedef struct siginfo {
#define si_addr_lsb _sifields._sigfault._addr_lsb
#define si_lower _sifields._sigfault._addr_bnd._lower
#define si_upper _sifields._sigfault._addr_bnd._upper
-#define si_pkey _sifields._sigfault._pkey
+#define si_pkey _sifields._sigfault._addr_pkey._pkey
#define si_band _sifields._sigpoll._band
#define si_fd _sifields._sigpoll._fd
#define si_call_addr _sifields._sigsys._call_addr
--
2.14.1

2018-01-16 00:45:32

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 14/22] signal/powerpc: Remove redefinition of NSIGTRAP on powerpc

NSIGTRAP is 4 in the generic siginfo and powerpc just undefines
NSGTRAP and redefine it as 4. That accomplishes nothing so remove
the duplication.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/powerpc/include/uapi/asm/siginfo.h | 3 ---
1 file changed, 3 deletions(-)

diff --git a/arch/powerpc/include/uapi/asm/siginfo.h b/arch/powerpc/include/uapi/asm/siginfo.h
index 444ca6c9989a..9f142451a01f 100644
--- a/arch/powerpc/include/uapi/asm/siginfo.h
+++ b/arch/powerpc/include/uapi/asm/siginfo.h
@@ -15,9 +15,6 @@

#include <asm-generic/siginfo.h>

-#undef NSIGTRAP
-#define NSIGTRAP 4
-
/*
* SIGFPE si_codes
*/
--
2.14.1

2018-01-16 00:46:08

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 21/22] signal: Remove the code to clear siginfo before calling copy_siginfo_from_user32

The new unified copy_siginfo_from_user32 takes care of this.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
kernel/ptrace.c | 1 -
kernel/signal.c | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 84b1367935e4..ec4365da9be8 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -1226,7 +1226,6 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
break;

case PTRACE_SETSIGINFO:
- memset(&siginfo, 0, sizeof siginfo);
if (copy_siginfo_from_user32(
&siginfo, (struct compat_siginfo __user *) datap))
ret = -EFAULT;
diff --git a/kernel/signal.c b/kernel/signal.c
index 5211b1b57163..bebe44265b8b 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3155,7 +3155,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
int, sig,
struct compat_siginfo __user *, uinfo)
{
- siginfo_t info = {};
+ siginfo_t info;
int ret = copy_siginfo_from_user32(&info, uinfo);
if (unlikely(ret))
return ret;
@@ -3199,7 +3199,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
int, sig,
struct compat_siginfo __user *, uinfo)
{
- siginfo_t info = {};
+ siginfo_t info;

if (copy_siginfo_from_user32(&info, uinfo))
return -EFAULT;
--
2.14.1

2018-01-16 00:46:11

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 19/22] signal/blackfin: Remove pointless UID16_SIGINFO_COMPAT_NEEDED

Nothing tests this define so just remove it.

I suspect the intention was to make the uid field in siginfo 16bit
however I can't find any code that ever tested this defined, and
even if it did it the layout has been this way for 8 years so
changing it now would break the ABI with userspace.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/blackfin/include/uapi/asm/siginfo.h | 2 --
1 file changed, 2 deletions(-)

diff --git a/arch/blackfin/include/uapi/asm/siginfo.h b/arch/blackfin/include/uapi/asm/siginfo.h
index 8c505170f4d0..2dd8c9c39248 100644
--- a/arch/blackfin/include/uapi/asm/siginfo.h
+++ b/arch/blackfin/include/uapi/asm/siginfo.h
@@ -11,8 +11,6 @@
#include <linux/types.h>
#include <asm-generic/siginfo.h>

-#define UID16_SIGINFO_COMPAT_NEEDED
-
#define si_uid16 _sifields._kill._uid

#endif /* _UAPI_BFIN_SIGINFO_H */
--
2.14.1

2018-01-16 00:46:13

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 15/22] signal/ia64: Move the ia64 specific si_codes to asm-generic/siginfo.h

Having si_codes in many different files simply encourages duplicate
definitions that can cause problems later. To avoid that merge the
ia64 specific si_codes into uapi/asm-generic/siginfo.h

Update the sanity checks in arch/x86/kernel/signal_compat.c to expect
the now lager NSIGILL and NSIGFPE. As nothing excpe the larger count
is exposed on x86 no additional code needs to be updated.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/ia64/include/uapi/asm/siginfo.h | 27 ---------------------------
arch/x86/kernel/signal_compat.c | 4 ++--
include/uapi/asm-generic/siginfo.h | 22 +++++++++++++++++++---
3 files changed, 21 insertions(+), 32 deletions(-)

diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h
index 66839031b767..5aa454ed89db 100644
--- a/arch/ia64/include/uapi/asm/siginfo.h
+++ b/arch/ia64/include/uapi/asm/siginfo.h
@@ -27,38 +27,11 @@
#define __ISR_VALID_BIT 0
#define __ISR_VALID (1 << __ISR_VALID_BIT)

-/*
- * SIGILL si_codes
- */
-#define ILL_BADIADDR 9 /* unimplemented instruction address */
-#define __ILL_BREAK 10 /* illegal break */
-#define __ILL_BNDMOD 11 /* bundle-update (modification) in progress */
-#undef NSIGILL
-#define NSIGILL 11
-
/*
* SIGFPE si_codes
*/
#ifdef __KERNEL__
#define FPE_FIXME 0 /* Broken dup of SI_USER */
#endif /* __KERNEL__ */
-#define __FPE_DECOVF 9 /* decimal overflow */
-#define __FPE_DECDIV 10 /* decimal division by zero */
-#define __FPE_DECERR 11 /* packed decimal error */
-#define __FPE_INVASC 12 /* invalid ASCII digit */
-#define __FPE_INVDEC 13 /* invalid decimal digit */
-#undef NSIGFPE
-#define NSIGFPE 13
-
-/*
- * SIGSEGV si_codes
- */
-#define __SEGV_PSTKOVF 4 /* paragraph stack overflow */
-#undef NSIGSEGV
-#define NSIGSEGV 4
-
-#undef NSIGTRAP
-#define NSIGTRAP 4
-

#endif /* _UAPI_ASM_IA64_SIGINFO_H */
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index 27495909932d..feb3ac135d0c 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -25,8 +25,8 @@ static inline void signal_compat_build_tests(void)
* limits also have to look at this code. Make sure any
* new fields are handled in copy_siginfo_to_user32()!
*/
- BUILD_BUG_ON(NSIGILL != 8);
- BUILD_BUG_ON(NSIGFPE != 8);
+ BUILD_BUG_ON(NSIGILL != 11);
+ BUILD_BUG_ON(NSIGFPE != 13);
BUILD_BUG_ON(NSIGSEGV != 4);
BUILD_BUG_ON(NSIGBUS != 5);
BUILD_BUG_ON(NSIGTRAP != 4);
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index eef4d778a5d4..2f0ae4607603 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -186,7 +186,12 @@ typedef struct siginfo {
#define ILL_PRVREG 6 /* privileged register */
#define ILL_COPROC 7 /* coprocessor error */
#define ILL_BADSTK 8 /* internal stack error */
-#define NSIGILL 8
+#ifdef __ia64__
+# define ILL_BADIADDR 9 /* unimplemented instruction address */
+# define __ILL_BREAK 10 /* illegal break */
+# define __ILL_BNDMOD 11 /* bundle-update (modification) in progress */
+#endif
+#define NSIGILL 11

/*
* SIGFPE si_codes
@@ -199,7 +204,14 @@ typedef struct siginfo {
#define FPE_FLTRES 6 /* floating point inexact result */
#define FPE_FLTINV 7 /* floating point invalid operation */
#define FPE_FLTSUB 8 /* subscript out of range */
-#define NSIGFPE 8
+#ifdef __ia64__
+# define __FPE_DECOVF 9 /* decimal overflow */
+# define __FPE_DECDIV 10 /* decimal division by zero */
+# define __FPE_DECERR 11 /* packed decimal error */
+# define __FPE_INVASC 12 /* invalid ASCII digit */
+# define __FPE_INVDEC 13 /* invalid decimal digit */
+#endif
+#define NSIGFPE 13

/*
* SIGSEGV si_codes
@@ -207,7 +219,11 @@ typedef struct siginfo {
#define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
#define SEGV_BNDERR 3 /* failed address bound checks */
-#define SEGV_PKUERR 4 /* failed protection key checks */
+#ifdef __ia64__
+# define __SEGV_PSTKOVF 4 /* paragraph stack overflow */
+#else
+# define SEGV_PKUERR 4 /* failed protection key checks */
+#endif
#define NSIGSEGV 4

/*
--
2.14.1

2018-01-16 00:46:56

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 03/22] signal: Document glibc's si_code of SI_ASYNCNL

The header uapi/asm-generic/siginfo.h appears to the the repository of
all of these definitions in linux so collect up glibcs additions as
well. Just to prevent someone from accidentally creating a conflict
in the future.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/uapi/asm-generic/siginfo.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 7158421ac911..2d3348afb2f0 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -165,6 +165,7 @@ typedef struct siginfo {
#define SI_SIGIO -5 /* sent by queued SIGIO */
#define SI_TKILL -6 /* sent by tkill system call */
#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */
+#define SI_ASYNCNL -60 /* sent by glibc async name lookup completion */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
--
2.14.1

2018-01-16 17:24:15

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Mon, Jan 15, 2018 at 11:23:03AM -0600, Eric W. Biederman wrote:
> Dave Martin <[email protected]> writes:
>
> > On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
> >> Setting si_code to 0 results in a userspace seeing an si_code of 0.
> >> This is the same si_code as SI_USER. Posix and common sense requires
> >> that SI_USER not be a signal specific si_code. As such this use of 0
> >> for the si_code is a pretty horribly broken ABI.
> >
> > I think this situation may have come about because 0 is used as a
> > padding value for "impossible" cases -- i.e., things that can't happen
> > unless the kernel is broken, or things that are too unrecoverable for
> > clean error reporting to be helpful.
> >
> > In general, I think these values are not expected to reach userspace in
> > practice.
> >
> > This is not an excuse though -- and not 100% true -- so it's certainly
> > worthy of cleanup.
> >
> >
> > It would be good to approach this similarly for arm and arm64, since
> > the arm64 fault code is derived from arm.
>
> In this case the fault_info is something I have only seen on arm64.
> I have been approaching all architectures the same way.

Bad guess on my part; this table-driven approach seems to be new for
arm64.

> If there is insufficient information without architecture expertise
> to fix this class of error I have been ading FPE_FIXME to them.

Fair enough.

> >> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
> >> value of __SI_KILL and now sees a value of SIL_KILL with the result
> >> that uid and pid fields are copied and which might copying the si_addr
> >> field by accident but certainly not by design. Making this a very
> >> flakey implementation.
> >>
> >> Utilizing FPE_FIXME, BUS_FIXME, TRAP_FIXME siginfo_layout will now return
> >> SIL_FAULT and the appropriate fields will be reliably copied.
> >>
> >> But folks this is a new and unique kind of bad. This is massively
> >> untested code bad. This is inventing new and unique was to get
> >> siginfo wrong bad. This is don't even think about Posix or what
> >> siginfo means bad. This is lots of eyeballs all missing the fact
> >> that the code does the wrong thing bad. This is getting stuck
> >> and keep making the same mistake bad.
> >>
> >> I really hope we can find a non userspace breaking fix for this on a
> >> port as new as arm64.
> >
> >> Possible ABI fixes include:
> >> - Send the signal without siginfo
> >> - Don't generate a signal
> >
> > The above two sould like ABI breaks?
>
> They are ways I have seen code on other platforms deal with
> not information to generate siginfo. Sending the signal without siginfo
> is roughly equivalent to your send SIGKILL suggestion below.
>
> A good example of that is code that calls force_sigsegv.
>
> Calling "force_sig(SIGBUS, current);" is perfectly valid.
> And then the parent when it reaped the process would have
> a little more information to go on when guessing what happened
> to the process.
>
> >> - Possibly assign and use an appropriate si_code
> >> - Don't handle cases which can't happen
> >
> > I think a mixture of these two is the best approach.
> >
> > In any case, si_code == 0 here doesn't seem to have any explicit meaning.
> > I think we can translate all of the arm64 faults to proper si_codes --
> > see my sketch below. Probably means a bit more thought though.
>
> Yes I would be very happy to see that.
>
> > The only counterargument would be if there is software relying on
> > these bogus signal cases getting si_code == 0 for a useful purpose.
> >
> > The main reason I see to check for SI_USER is to allow a process to
> > filter out spurious signals (say, an asynchronous I/O signal for
> > which si_value would be garbage), and to print out diagnostics
> > before (in the case of a well-behaved program) resetting the signal
> > to SIG_DFL and killing itself to report the signal to the waiter.
> >
> > Daemons may be more discerning about who is allowed to signal them,
> > but overloading SIGBUS (say) as an IPC channel sounds like a very odd
> > thing to do. The same probably applies to any signal that has
> > nontrivial metadata.
>
> Agreed. Although I have seen ltp test cases that do crazy things like
> that.
>
> > Have you found software that is impacted by this in practice?
>
> No.

Searching for si_code on codesearch.debian.net, I looked at a few
random hits. Although this is far from exhaustive, I saw no instance
of code that assumes some arch-specific meaning for SI_USER (or 0).

Most code seems to check for signal-specific si_code values before
assuming that signal-specific signifo fields are valid; or for
SI_USER (or si_code <= 0) before assuming that si_uid and si_pid
are valid.

Returning proper values for si_code values in place of "0" would fix
rather than break such cases.


> I don't expect many userspace applications look at siginfo and
> everything I have found is some rare hard to trigger non-x86 case which
> limits the exposure to userspace applications tremendously.
>
> The angle I am coming at all of this from is that the linux kernel code
> that filled out out struct siginfo was not comprehensible or correct.

I think "not comprehensible or correct" is a pretty good summary of
all signal-related code...

> Internal to the kernel it was using a magic value (not exportable to
> userspace) in the upper bits of si_code. That was causing problems for
> signal injection and converting signals from 32bit to 64bit, and from
> 64bit to 32bit.
>
> So I wrote kernel/signal.c:siginfo_layout() to figure out which fields
> of struct siginfo should be sent to userspace. In doing so I discovered
> that using 0 in si_code (aka SI_USER) is ambiguous, and problematic.
>
> Unfortuantely in most of the cases I have spotted using 0 in the si_code
> requires architectural knowledge that I don't currently have to sort
> out. So the best I can do is change si_code from 0 to
> FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers
> attention to this area.
>
> One of the problems that results from all of this is that we copy
> unitialized data to userspace. I am slowly unifying and cleaning the
> code up so that the code is simple enough we can be certain we are
> not copying unitialized data to userspace.
>
> With si_coes of FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to
> keep the craziness from happening.
>
> My next step is to unify struct siginfo and struct compat_siginfo
> and the functions that copy them to userspace because there are very
> siginficant problems there.

All of which sounds valuable.

> All of that said I like the way you are thinking about fixing these
> issues.

Is it feasible to have a different internal constant for SI_USER?
Then the generic could warn if it sees si_code == 0. If the
special nonzero KERNEL_SI_USER is seen instead, it is silently
translated to SI_USER (0) for userspace. This might help us
track down cases where 0 is passed by accident.

It may not be worth it though: if the affected cases are ones
that happen never or almost never, a runtime BUG_ON() may not be
helpful for tracking them down.

Also, I'm making an assumption that si_code always flows through
some generic code before reaching userspace (maybe untrue).


> >> +++ b/arch/arm64/kernel/fpsimd.c
> >> @@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
> >> asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
> >> {
> >> siginfo_t info;
> >> - unsigned int si_code = 0;
> >> + unsigned int si_code = FPE_FIXME;
> >>
> >> if (esr & FPEXC_IOF)
> >> si_code = FPE_FLTINV;
> >
> > This 0 can happen for vector operations where the implementation may
> > not be able to report exactly what happened, for example where
> > the implementer didn't want to pay the cost of tracking exactly
> > what went wrong in each lane.
> >
> > However, the FPEXC_* bits can be garbage in such a case rather
> > than being all zero: we should be checking the TFV bit in the ESR here.
> > This may be a bug.
> >
> > Perhaps FPE_FLTINV should be returned in si_code for such cases: it's
> > not otherwise used on arm64 -- invalid instructions would be reported as
> > SIGILL/ILL_ILLOPC instead).
> >
> > Otherwise, we might want to define a new code or arbitrarily pick
> > one of the existing FLT_* since this is really a more benign condition
> > than executing an illegal instruction. Alternatively, treat the
> > fault as spurious and suppress it, but that doesn't feel right either.
>
> I would love to see this sorted out. There is a very similar pattern
> on several different architectures. I suspect if we have a clean
> solution on one architecture the other architectures will be able to use
> that solution as well.

Since user code that relies on checking si_code for fp exceptions will
probably already break in these cases, we can probably fudge things a
bit here.

I'll have a think. IEEE may also define some rules that are relevant
here...

For the proposed conversion of the si_code==0 cases for arm64, I'll
draft an RFC for discussion (hopefully sometime this week).

[...]

Cheers
---Dave

2018-01-16 17:41:27

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE

On Mon, Jan 15, 2018 at 05:49:47PM +0000, Russell King - ARM Linux wrote:
> On Thu, Jan 11, 2018 at 06:59:37PM -0600, Eric W. Biederman wrote:
> > Setting si_code to 0 results in a userspace seeing an si_code of 0.
> > This is the same si_code as SI_USER. Posix and common sense requires
> > that SI_USER not be a signal specific si_code. As such this use of 0
> > for the si_code is a pretty horribly broken ABI.
> >
> > Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
> > value of __SI_KILL and now sees a value of SIL_KILL with the result
> > that uid and pid fields are copied and which might copying the si_addr
> > field by accident but certainly not by design. Making this a very
> > flakey implementation.
> >
> > Utilizing FPE_FIXME, siginfo_layout will now return SIL_FAULT and the
> > appropriate fields will be reliably copied.
>
> So what do you suggest when none of the SIGFPE FPE_xxx codes match the
> condition that "we don't know what happened" ? Raise a SIGKILL instead
> maybe? We will have dumped the VFP state into the kernel log at this
> point, things are pretty much fscked.
>
> It's probably an impossible condition unless the hardware has failed,
> no one has knowingly reported getting such a dump in their kernel log,
> so it's something that could very likely be changed in some way
> without anyone noticing.

arm64 can optionally not tell you exactly what exception(s) happened for
vector operations. This may also be true for 32-bit.

Unfortunately, there's nothing sensible to report in this case, and
there is no such constant as FPE_UNKNOWN.

Currently arm64 sets si_code to 0, which doesn't match any FPE_*
constant (but unfortunately matches SI_USER) -- defining a new, distinct
FPE_UNKNOWN is probably no worse than that.

I'm not sure yet whether a similar argument applies for 32-bit.

Cheers
---Dave

2018-01-16 22:29:52

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

Dave Martin <[email protected]> writes:

> On Mon, Jan 15, 2018 at 11:23:03AM -0600, Eric W. Biederman wrote:
>> Dave Martin <[email protected]> writes:
>>
>> > On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
>> >> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>> >> This is the same si_code as SI_USER. Posix and common sense requires
>> >> that SI_USER not be a signal specific si_code. As such this use of 0
>> >> for the si_code is a pretty horribly broken ABI.
>> >
>> > I think this situation may have come about because 0 is used as a
>> > padding value for "impossible" cases -- i.e., things that can't happen
>> > unless the kernel is broken, or things that are too unrecoverable for
>> > clean error reporting to be helpful.
>> >
>> > In general, I think these values are not expected to reach userspace in
>> > practice.
>> >
>> > This is not an excuse though -- and not 100% true -- so it's certainly
>> > worthy of cleanup.
>> >
>> >
>> > It would be good to approach this similarly for arm and arm64, since
>> > the arm64 fault code is derived from arm.
>>
>> In this case the fault_info is something I have only seen on arm64.
>> I have been approaching all architectures the same way.
>
> Bad guess on my part; this table-driven approach seems to be new for
> arm64.
>
>> If there is insufficient information without architecture expertise
>> to fix this class of error I have been ading FPE_FIXME to them.
>
> Fair enough.
>
>> >> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>> >> value of __SI_KILL and now sees a value of SIL_KILL with the result
>> >> that uid and pid fields are copied and which might copying the si_addr
>> >> field by accident but certainly not by design. Making this a very
>> >> flakey implementation.
>> >>
>> >> Utilizing FPE_FIXME, BUS_FIXME, TRAP_FIXME siginfo_layout will now return
>> >> SIL_FAULT and the appropriate fields will be reliably copied.
>> >>
>> >> But folks this is a new and unique kind of bad. This is massively
>> >> untested code bad. This is inventing new and unique was to get
>> >> siginfo wrong bad. This is don't even think about Posix or what
>> >> siginfo means bad. This is lots of eyeballs all missing the fact
>> >> that the code does the wrong thing bad. This is getting stuck
>> >> and keep making the same mistake bad.
>> >>
>> >> I really hope we can find a non userspace breaking fix for this on a
>> >> port as new as arm64.
>> >
>> >> Possible ABI fixes include:
>> >> - Send the signal without siginfo
>> >> - Don't generate a signal
>> >
>> > The above two sould like ABI breaks?
>>
>> They are ways I have seen code on other platforms deal with
>> not information to generate siginfo. Sending the signal without siginfo
>> is roughly equivalent to your send SIGKILL suggestion below.
>>
>> A good example of that is code that calls force_sigsegv.
>>
>> Calling "force_sig(SIGBUS, current);" is perfectly valid.
>> And then the parent when it reaped the process would have
>> a little more information to go on when guessing what happened
>> to the process.
>>
>> >> - Possibly assign and use an appropriate si_code
>> >> - Don't handle cases which can't happen
>> >
>> > I think a mixture of these two is the best approach.
>> >
>> > In any case, si_code == 0 here doesn't seem to have any explicit meaning.
>> > I think we can translate all of the arm64 faults to proper si_codes --
>> > see my sketch below. Probably means a bit more thought though.
>>
>> Yes I would be very happy to see that.
>>
>> > The only counterargument would be if there is software relying on
>> > these bogus signal cases getting si_code == 0 for a useful purpose.
>> >
>> > The main reason I see to check for SI_USER is to allow a process to
>> > filter out spurious signals (say, an asynchronous I/O signal for
>> > which si_value would be garbage), and to print out diagnostics
>> > before (in the case of a well-behaved program) resetting the signal
>> > to SIG_DFL and killing itself to report the signal to the waiter.
>> >
>> > Daemons may be more discerning about who is allowed to signal them,
>> > but overloading SIGBUS (say) as an IPC channel sounds like a very odd
>> > thing to do. The same probably applies to any signal that has
>> > nontrivial metadata.
>>
>> Agreed. Although I have seen ltp test cases that do crazy things like
>> that.
>>
>> > Have you found software that is impacted by this in practice?
>>
>> No.
>
> Searching for si_code on codesearch.debian.net, I looked at a few
> random hits. Although this is far from exhaustive, I saw no instance
> of code that assumes some arch-specific meaning for SI_USER (or 0).
>
> Most code seems to check for signal-specific si_code values before
> assuming that signal-specific signifo fields are valid; or for
> SI_USER (or si_code <= 0) before assuming that si_uid and si_pid
> are valid.
>
> Returning proper values for si_code values in place of "0" would fix
> rather than break such cases.
>
>
>> I don't expect many userspace applications look at siginfo and
>> everything I have found is some rare hard to trigger non-x86 case which
>> limits the exposure to userspace applications tremendously.
>>
>> The angle I am coming at all of this from is that the linux kernel code
>> that filled out out struct siginfo was not comprehensible or correct.
>
> I think "not comprehensible or correct" is a pretty good summary of
> all signal-related code...
>
>> Internal to the kernel it was using a magic value (not exportable to
>> userspace) in the upper bits of si_code. That was causing problems for
>> signal injection and converting signals from 32bit to 64bit, and from
>> 64bit to 32bit.
>>
>> So I wrote kernel/signal.c:siginfo_layout() to figure out which fields
>> of struct siginfo should be sent to userspace. In doing so I discovered
>> that using 0 in si_code (aka SI_USER) is ambiguous, and problematic.
>>
>> Unfortuantely in most of the cases I have spotted using 0 in the si_code
>> requires architectural knowledge that I don't currently have to sort
>> out. So the best I can do is change si_code from 0 to
>> FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers
>> attention to this area.
>>
>> One of the problems that results from all of this is that we copy
>> unitialized data to userspace. I am slowly unifying and cleaning the
>> code up so that the code is simple enough we can be certain we are
>> not copying unitialized data to userspace.
>>
>> With si_coes of FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to
>> keep the craziness from happening.
>>
>> My next step is to unify struct siginfo and struct compat_siginfo
>> and the functions that copy them to userspace because there are very
>> siginficant problems there.
>
> All of which sounds valuable.
>
>> All of that said I like the way you are thinking about fixing these
>> issues.
>
> Is it feasible to have a different internal constant for SI_USER?
> Then the generic could warn if it sees si_code == 0. If the
> special nonzero KERNEL_SI_USER is seen instead, it is silently
> translated to SI_USER (0) for userspace. This might help us
> track down cases where 0 is passed by accident.
>
> It may not be worth it though: if the affected cases are ones
> that happen never or almost never, a runtime BUG_ON() may not be
> helpful for tracking them down.
>
> Also, I'm making an assumption that si_code always flows through
> some generic code before reaching userspace (maybe untrue).

The code does flow through a generic path, and I am in the middle of
tightening that up right now. As filling out siginfo is error prone,
and I need a guarantee that all of struct siginfo is initialized.
Adding a warning if a arch fault hander uses si_code == 0 aka SI_USER
would not be hard.

Given what you have found. Given that it seems to match my experience
we can almost certainly change the code to just warn when the 0 is
passed in for the si_code for fault handlers.

I want to ensure that all of the fields are filled in before I do that
or else I risk passing unitialized values to userspace. But I like that
as the long term goal for this code.

>> >> +++ b/arch/arm64/kernel/fpsimd.c
>> >> @@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
>> >> asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
>> >> {
>> >> siginfo_t info;
>> >> - unsigned int si_code = 0;
>> >> + unsigned int si_code = FPE_FIXME;
>> >>
>> >> if (esr & FPEXC_IOF)
>> >> si_code = FPE_FLTINV;
>> >
>> > This 0 can happen for vector operations where the implementation may
>> > not be able to report exactly what happened, for example where
>> > the implementer didn't want to pay the cost of tracking exactly
>> > what went wrong in each lane.
>> >
>> > However, the FPEXC_* bits can be garbage in such a case rather
>> > than being all zero: we should be checking the TFV bit in the ESR here.
>> > This may be a bug.
>> >
>> > Perhaps FPE_FLTINV should be returned in si_code for such cases: it's
>> > not otherwise used on arm64 -- invalid instructions would be reported as
>> > SIGILL/ILL_ILLOPC instead).
>> >
>> > Otherwise, we might want to define a new code or arbitrarily pick
>> > one of the existing FLT_* since this is really a more benign condition
>> > than executing an illegal instruction. Alternatively, treat the
>> > fault as spurious and suppress it, but that doesn't feel right either.
>>
>> I would love to see this sorted out. There is a very similar pattern
>> on several different architectures. I suspect if we have a clean
>> solution on one architecture the other architectures will be able to use
>> that solution as well.
>
> Since user code that relies on checking si_code for fp exceptions will
> probably already break in these cases, we can probably fudge things a
> bit here.
>
> I'll have a think. IEEE may also define some rules that are relevant
> here...
>
> For the proposed conversion of the si_code==0 cases for arm64, I'll
> draft an RFC for discussion (hopefully sometime this week).

Sounds good.

I will keep FPE_FIXME as a place holder until this gets sorted out.

There is a second issue I am looking at in this location,
and maybe I don't have to address it now. But it looks like the code is
calling send_sig_info instead of force_sig_info for a synchronous
exception. Am I reading that correctly?

Eric

2018-01-17 11:46:22

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Tue, Jan 16, 2018 at 04:28:50PM -0600, Eric W. Biederman wrote:
> Dave Martin <[email protected]> writes:
>
> > On Mon, Jan 15, 2018 at 11:23:03AM -0600, Eric W. Biederman wrote:
> >> Dave Martin <[email protected]> writes:
> >>
> >> > On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
> >> >> Setting si_code to 0 results in a userspace seeing an si_code of 0.
> >> >> This is the same si_code as SI_USER. Posix and common sense requires
> >> >> that SI_USER not be a signal specific si_code. As such this use of 0
> >> >> for the si_code is a pretty horribly broken ABI.
> >> >
> >> > I think this situation may have come about because 0 is used as a
> >> > padding value for "impossible" cases -- i.e., things that can't happen
> >> > unless the kernel is broken, or things that are too unrecoverable for
> >> > clean error reporting to be helpful.
> >> >
> >> > In general, I think these values are not expected to reach userspace in
> >> > practice.
> >> >
> >> > This is not an excuse though -- and not 100% true -- so it's certainly
> >> > worthy of cleanup.
> >> >
> >> >
> >> > It would be good to approach this similarly for arm and arm64, since
> >> > the arm64 fault code is derived from arm.
> >>
> >> In this case the fault_info is something I have only seen on arm64.
> >> I have been approaching all architectures the same way.
> >
> > Bad guess on my part; this table-driven approach seems to be new for
> > arm64.
> >
> >> If there is insufficient information without architecture expertise
> >> to fix this class of error I have been ading FPE_FIXME to them.
> >
> > Fair enough.
> >
> >> >> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
> >> >> value of __SI_KILL and now sees a value of SIL_KILL with the result
> >> >> that uid and pid fields are copied and which might copying the si_addr
> >> >> field by accident but certainly not by design. Making this a very
> >> >> flakey implementation.
> >> >>
> >> >> Utilizing FPE_FIXME, BUS_FIXME, TRAP_FIXME siginfo_layout will now return
> >> >> SIL_FAULT and the appropriate fields will be reliably copied.
> >> >>
> >> >> But folks this is a new and unique kind of bad. This is massively
> >> >> untested code bad. This is inventing new and unique was to get
> >> >> siginfo wrong bad. This is don't even think about Posix or what
> >> >> siginfo means bad. This is lots of eyeballs all missing the fact
> >> >> that the code does the wrong thing bad. This is getting stuck
> >> >> and keep making the same mistake bad.
> >> >>
> >> >> I really hope we can find a non userspace breaking fix for this on a
> >> >> port as new as arm64.
> >> >
> >> >> Possible ABI fixes include:
> >> >> - Send the signal without siginfo
> >> >> - Don't generate a signal
> >> >
> >> > The above two sould like ABI breaks?
> >>
> >> They are ways I have seen code on other platforms deal with
> >> not information to generate siginfo. Sending the signal without siginfo
> >> is roughly equivalent to your send SIGKILL suggestion below.
> >>
> >> A good example of that is code that calls force_sigsegv.
> >>
> >> Calling "force_sig(SIGBUS, current);" is perfectly valid.
> >> And then the parent when it reaped the process would have
> >> a little more information to go on when guessing what happened
> >> to the process.
> >>
> >> >> - Possibly assign and use an appropriate si_code
> >> >> - Don't handle cases which can't happen
> >> >
> >> > I think a mixture of these two is the best approach.
> >> >
> >> > In any case, si_code == 0 here doesn't seem to have any explicit meaning.
> >> > I think we can translate all of the arm64 faults to proper si_codes --
> >> > see my sketch below. Probably means a bit more thought though.
> >>
> >> Yes I would be very happy to see that.
> >>
> >> > The only counterargument would be if there is software relying on
> >> > these bogus signal cases getting si_code == 0 for a useful purpose.
> >> >
> >> > The main reason I see to check for SI_USER is to allow a process to
> >> > filter out spurious signals (say, an asynchronous I/O signal for
> >> > which si_value would be garbage), and to print out diagnostics
> >> > before (in the case of a well-behaved program) resetting the signal
> >> > to SIG_DFL and killing itself to report the signal to the waiter.
> >> >
> >> > Daemons may be more discerning about who is allowed to signal them,
> >> > but overloading SIGBUS (say) as an IPC channel sounds like a very odd
> >> > thing to do. The same probably applies to any signal that has
> >> > nontrivial metadata.
> >>
> >> Agreed. Although I have seen ltp test cases that do crazy things like
> >> that.
> >>
> >> > Have you found software that is impacted by this in practice?
> >>
> >> No.
> >
> > Searching for si_code on codesearch.debian.net, I looked at a few
> > random hits. Although this is far from exhaustive, I saw no instance
> > of code that assumes some arch-specific meaning for SI_USER (or 0).
> >
> > Most code seems to check for signal-specific si_code values before
> > assuming that signal-specific signifo fields are valid; or for
> > SI_USER (or si_code <= 0) before assuming that si_uid and si_pid
> > are valid.
> >
> > Returning proper values for si_code values in place of "0" would fix
> > rather than break such cases.
> >
> >
> >> I don't expect many userspace applications look at siginfo and
> >> everything I have found is some rare hard to trigger non-x86 case which
> >> limits the exposure to userspace applications tremendously.
> >>
> >> The angle I am coming at all of this from is that the linux kernel code
> >> that filled out out struct siginfo was not comprehensible or correct.
> >
> > I think "not comprehensible or correct" is a pretty good summary of
> > all signal-related code...
> >
> >> Internal to the kernel it was using a magic value (not exportable to
> >> userspace) in the upper bits of si_code. That was causing problems for
> >> signal injection and converting signals from 32bit to 64bit, and from
> >> 64bit to 32bit.
> >>
> >> So I wrote kernel/signal.c:siginfo_layout() to figure out which fields
> >> of struct siginfo should be sent to userspace. In doing so I discovered
> >> that using 0 in si_code (aka SI_USER) is ambiguous, and problematic.
> >>
> >> Unfortuantely in most of the cases I have spotted using 0 in the si_code
> >> requires architectural knowledge that I don't currently have to sort
> >> out. So the best I can do is change si_code from 0 to
> >> FPE_FIXME/BUS_FIXME/TRAP_FIXME and bring the architecture maintainers
> >> attention to this area.
> >>
> >> One of the problems that results from all of this is that we copy
> >> unitialized data to userspace. I am slowly unifying and cleaning the
> >> code up so that the code is simple enough we can be certain we are
> >> not copying unitialized data to userspace.
> >>
> >> With si_coes of FPE_FIXME/BUS_FIXME/TRAP_FIXME I can at least attempt to
> >> keep the craziness from happening.
> >>
> >> My next step is to unify struct siginfo and struct compat_siginfo
> >> and the functions that copy them to userspace because there are very
> >> siginficant problems there.
> >
> > All of which sounds valuable.
> >
> >> All of that said I like the way you are thinking about fixing these
> >> issues.
> >
> > Is it feasible to have a different internal constant for SI_USER?
> > Then the generic could warn if it sees si_code == 0. If the
> > special nonzero KERNEL_SI_USER is seen instead, it is silently
> > translated to SI_USER (0) for userspace. This might help us
> > track down cases where 0 is passed by accident.
> >
> > It may not be worth it though: if the affected cases are ones
> > that happen never or almost never, a runtime BUG_ON() may not be
> > helpful for tracking them down.
> >
> > Also, I'm making an assumption that si_code always flows through
> > some generic code before reaching userspace (maybe untrue).
>
> The code does flow through a generic path, and I am in the middle of
> tightening that up right now. As filling out siginfo is error prone,
> and I need a guarantee that all of struct siginfo is initialized.
> Adding a warning if a arch fault hander uses si_code == 0 aka SI_USER
> would not be hard.
>
> Given what you have found. Given that it seems to match my experience
> we can almost certainly change the code to just warn when the 0 is
> passed in for the si_code for fault handlers.
>
> I want to ensure that all of the fields are filled in before I do that
> or else I risk passing unitialized values to userspace. But I like that
> as the long term goal for this code.
>
> >> >> +++ b/arch/arm64/kernel/fpsimd.c
> >> >> @@ -867,7 +867,7 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
> >> >> asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
> >> >> {
> >> >> siginfo_t info;
> >> >> - unsigned int si_code = 0;
> >> >> + unsigned int si_code = FPE_FIXME;
> >> >>
> >> >> if (esr & FPEXC_IOF)
> >> >> si_code = FPE_FLTINV;
> >> >
> >> > This 0 can happen for vector operations where the implementation may
> >> > not be able to report exactly what happened, for example where
> >> > the implementer didn't want to pay the cost of tracking exactly
> >> > what went wrong in each lane.
> >> >
> >> > However, the FPEXC_* bits can be garbage in such a case rather
> >> > than being all zero: we should be checking the TFV bit in the ESR here.
> >> > This may be a bug.
> >> >
> >> > Perhaps FPE_FLTINV should be returned in si_code for such cases: it's
> >> > not otherwise used on arm64 -- invalid instructions would be reported as
> >> > SIGILL/ILL_ILLOPC instead).
> >> >
> >> > Otherwise, we might want to define a new code or arbitrarily pick
> >> > one of the existing FLT_* since this is really a more benign condition
> >> > than executing an illegal instruction. Alternatively, treat the
> >> > fault as spurious and suppress it, but that doesn't feel right either.
> >>
> >> I would love to see this sorted out. There is a very similar pattern
> >> on several different architectures. I suspect if we have a clean
> >> solution on one architecture the other architectures will be able to use
> >> that solution as well.
> >
> > Since user code that relies on checking si_code for fp exceptions will
> > probably already break in these cases, we can probably fudge things a
> > bit here.
> >
> > I'll have a think. IEEE may also define some rules that are relevant
> > here...
> >
> > For the proposed conversion of the si_code==0 cases for arm64, I'll
> > draft an RFC for discussion (hopefully sometime this week).
>
> Sounds good.
>
> I will keep FPE_FIXME as a place holder until this gets sorted out.
>
> There is a second issue I am looking at in this location,
> and maybe I don't have to address it now. But it looks like the code is
> calling send_sig_info instead of force_sig_info for a synchronous
> exception. Am I reading that correctly?

You mean floating-point exception? (almost anything that is not an
interrupt can be a sunchronous exception on arm64).

Interesting though. arm and arm64 have send_sig_info() here, but
all other arches seem to have force_sig_info().

sigaction(2) says:
"According to POSIX, the behavior of a process is undefined after it
ignores a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by
kill(2) or raise(3)."

I can't find the POSIX reference for this, but the above suggests we
don't _have_ to kill the process. arm/arm64 do seem inconsistent on
this though, compared with other architectures. force_sig_info() might
be needed to avoid a spin on architectures where writeback is
suppressed when a precise fp exception trap is taken and the exception
return address points back to the offending instruction. I'm
struggling to deduce from the ARM ARM whether this applies here.

Maybe it doesn't matter what we do: the state of the standards seems
to mean that user code that attempts to recover from FP exceptions
will be nonportable and probably broken in any case...


Russell, do you remember the motivation for this? I'm looking at
da41119af788 ("[PATCH] ARM: Don't force SIGFPE")

Cheers
---Dave

-8<-

From: Russell King <[email protected]>
Date: Wed, 29 Jun 2005 23:02:02 +0100
Subject: [PATCH 1/1] [PATCH] ARM: Don't force SIGFPE

We were forcing SIGFPE on to a user program for no good reason.
Use send_sig_info() instead.

Signed-off-by: Russell King <[email protected]>
---
arch/arm/vfp/vfpmodule.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 3aeedd2..22f3da4 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -89,7 +89,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
current->thread.error_code = 0;
current->thread.trap_no = 6;

- force_sig_info(SIGFPE, &info, current);
+ send_sig_info(SIGFPE, &info, current);
}

static void vfp_panic(char *reason)
--
2.1.4

2018-01-17 11:57:51

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Tue, Jan 16, 2018 at 04:28:50PM -0600, Eric W. Biederman wrote:
> I will keep FPE_FIXME as a place holder until this gets sorted out.
>
> There is a second issue I am looking at in this location,
> and maybe I don't have to address it now. But it looks like the code is
> calling send_sig_info instead of force_sig_info for a synchronous
> exception. Am I reading that correctly?

VFP used to use force_sig_info(), but it seems to be really the wrong
call to use. force_sig_info() checks whether the program decided to
ignore or block the signal, and if it did, replaces the signal handler
with the default handler and unblocks the signal.

Are you really suggesting that FP all FP signals should get this
treatment?

--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

2018-01-17 12:15:13

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Wed, Jan 17, 2018 at 11:57:09AM +0000, Russell King - ARM Linux wrote:
> On Tue, Jan 16, 2018 at 04:28:50PM -0600, Eric W. Biederman wrote:
> > I will keep FPE_FIXME as a place holder until this gets sorted out.
> >
> > There is a second issue I am looking at in this location,
> > and maybe I don't have to address it now. But it looks like the code is
> > calling send_sig_info instead of force_sig_info for a synchronous
> > exception. Am I reading that correctly?
>
> VFP used to use force_sig_info(), but it seems to be really the wrong
> call to use. force_sig_info() checks whether the program decided to
> ignore or block the signal, and if it did, replaces the signal handler
> with the default handler and unblocks the signal.
>
> Are you really suggesting that FP all FP signals should get this
> treatment?

feenableexcept(FE_OVERFLOW) kind of means "I can't run safely past
an fp overflow exception, please signal me instead".

If the process also blocked SIGFPE, that could be taken to mean
"I can't run safely past an fp overflow exception _and_ I can't
take SIGFPE either" ... i.e., if an fp overflow happens there is
no way to proceed and it's really fatal.

What SIG_IGN ought to mean is rather more debatable, but again,
the process could be asking for two opposite things: guarantee a
SIGFPE is delivered instead of running past an fp exception, and
also guarantee that SIGFPE is _not_ delivered.

It looks like arm and arm64 are different from most other arches
(including x86) here, but I'm not sure what is considered correct, and
it looks like the answer is not standardised. There's a possibility
that some software goes subtly wrong on arm/arm64 where on other arches
it would get terminated with SIGKILL.

Whether this matters depends on how harmless the fp exception is to
the work of the program. I think if an exception is set to trap
via feenableexcept() then that's a strong hint the programmer thinks
that exception is not harmless. OTOH, trapping is not always
available anyway...


Was there some particular program being broken by the force_sig_info()
here?

Cheers
---Dave

2018-01-17 12:38:16

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Wed, Jan 17, 2018 at 12:15:05PM +0000, Dave Martin wrote:
> On Wed, Jan 17, 2018 at 11:57:09AM +0000, Russell King - ARM Linux wrote:
> > On Tue, Jan 16, 2018 at 04:28:50PM -0600, Eric W. Biederman wrote:
> > > I will keep FPE_FIXME as a place holder until this gets sorted out.
> > >
> > > There is a second issue I am looking at in this location,
> > > and maybe I don't have to address it now. But it looks like the code is
> > > calling send_sig_info instead of force_sig_info for a synchronous
> > > exception. Am I reading that correctly?
> >
> > VFP used to use force_sig_info(), but it seems to be really the wrong
> > call to use. force_sig_info() checks whether the program decided to
> > ignore or block the signal, and if it did, replaces the signal handler
> > with the default handler and unblocks the signal.
> >
> > Are you really suggesting that FP all FP signals should get this
> > treatment?
>
> feenableexcept(FE_OVERFLOW) kind of means "I can't run safely past
> an fp overflow exception, please signal me instead".
>
> If the process also blocked SIGFPE, that could be taken to mean
> "I can't run safely past an fp overflow exception _and_ I can't
> take SIGFPE either" ... i.e., if an fp overflow happens there is
> no way to proceed and it's really fatal.
>
> What SIG_IGN ought to mean is rather more debatable, but again,
> the process could be asking for two opposite things: guarantee a
> SIGFPE is delivered instead of running past an fp exception, and
> also guarantee that SIGFPE is _not_ delivered.
>
> It looks like arm and arm64 are different from most other arches
> (including x86) here, but I'm not sure what is considered correct, and
> it looks like the answer is not standardised. There's a possibility
> that some software goes subtly wrong on arm/arm64 where on other arches
> it would get terminated with SIGKILL.
>
> Whether this matters depends on how harmless the fp exception is to
> the work of the program. I think if an exception is set to trap
> via feenableexcept() then that's a strong hint the programmer thinks
> that exception is not harmless. OTOH, trapping is not always
> available anyway...

Like many of these things, there is no clear answer. It's a set of
conflicting requirements, and as you point out, even if you've called
feenableexcept(), you are not guaranteed to get a trap.

However, do remember that FP exceptions on ARM hardware are already
asynchronous - they get reported by the _next_ FP operation to the one
that caused them, which means they could be raised by a library function
sometime after it occured (when the library function decides to save the
FP registers to the stack before it makes use of them.) It's entirely
possible that the library function has blocked FP signals temporarily
(not explicitly, just decided to block all signals while it does
something sensitive) and will unblock them again afterwards - at which
point we get the SIGFPE, and it would be quite right to deliver that
signal to the user SIGFPE handler, rather than forcing it onto the
program mid-library function.

It's also possible that SIGFPE could be blocked by another signal handler
having been invoked, and it triggers the latent generation of the SIGFPE.

I'd be more inclined to agree with you if VFP exceptions were synchronous
but they aren't.

> Was there some particular program being broken by the force_sig_info()
> here?

I don't recall.

--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

2018-01-17 15:38:16

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Wed, Jan 17, 2018 at 12:37:52PM +0000, Russell King - ARM Linux wrote:
> On Wed, Jan 17, 2018 at 12:15:05PM +0000, Dave Martin wrote:
> > On Wed, Jan 17, 2018 at 11:57:09AM +0000, Russell King - ARM Linux wrote:

[...]

> > > VFP used to use force_sig_info(), but it seems to be really the wrong
> > > call to use. force_sig_info() checks whether the program decided to
> > > ignore or block the signal, and if it did, replaces the signal handler
> > > with the default handler and unblocks the signal.
> > >
> > > Are you really suggesting that FP all FP signals should get this
> > > treatment?
> >
> > feenableexcept(FE_OVERFLOW) kind of means "I can't run safely past
> > an fp overflow exception, please signal me instead".
> >
> > If the process also blocked SIGFPE, that could be taken to mean
> > "I can't run safely past an fp overflow exception _and_ I can't
> > take SIGFPE either" ... i.e., if an fp overflow happens there is
> > no way to proceed and it's really fatal.
> >
> > What SIG_IGN ought to mean is rather more debatable, but again,
> > the process could be asking for two opposite things: guarantee a
> > SIGFPE is delivered instead of running past an fp exception, and
> > also guarantee that SIGFPE is _not_ delivered.
> >
> > It looks like arm and arm64 are different from most other arches
> > (including x86) here, but I'm not sure what is considered correct, and
> > it looks like the answer is not standardised. There's a possibility
> > that some software goes subtly wrong on arm/arm64 where on other arches
> > it would get terminated with SIGKILL.
> >
> > Whether this matters depends on how harmless the fp exception is to
> > the work of the program. I think if an exception is set to trap
> > via feenableexcept() then that's a strong hint the programmer thinks
> > that exception is not harmless. OTOH, trapping is not always
> > available anyway...
>
> Like many of these things, there is no clear answer. It's a set of
> conflicting requirements, and as you point out, even if you've called
> feenableexcept(), you are not guaranteed to get a trap.
>
> However, do remember that FP exceptions on ARM hardware are already
> asynchronous - they get reported by the _next_ FP operation to the one
> that caused them, which means they could be raised by a library function
> sometime after it occured (when the library function decides to save the
> FP registers to the stack before it makes use of them.) It's entirely
> possible that the library function has blocked FP signals temporarily
> (not explicitly, just decided to block all signals while it does
> something sensitive) and will unblock them again afterwards - at which
> point we get the SIGFPE, and it would be quite right to deliver that
> signal to the user SIGFPE handler, rather than forcing it onto the
> program mid-library function.
>
> It's also possible that SIGFPE could be blocked by another signal handler
> having been invoked, and it triggers the latent generation of the SIGFPE.
>
> I'd be more inclined to agree with you if VFP exceptions were synchronous
> but they aren't.

Hmmm, it looks like imprecise fp exception traps are disallowed from
ARMv8 onwards. I guess they made more sense when the FPU really was a
coprocessor, or at least semidetached from the integer core.

I think force_sig_info() makes sense here if and only if the traps
are guaranteed to be precise, so we probably should use this on arm64.
Not arm though (alpha doesn't either, if I understand the code
correctly.)

Does that make sense?

Apparently, few recent cores (at least ARM's own ones) support fp
exception trapping anyway... 1176 may be the most recent.

Cheers
---Dave

2018-01-17 15:51:18

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Wed, Jan 17, 2018 at 03:37:31PM +0000, Dave Martin wrote:
> On Wed, Jan 17, 2018 at 12:37:52PM +0000, Russell King - ARM Linux wrote:
> > On Wed, Jan 17, 2018 at 12:15:05PM +0000, Dave Martin wrote:
> > > On Wed, Jan 17, 2018 at 11:57:09AM +0000, Russell King - ARM Linux wrote:
>
> [...]
>
> > > > VFP used to use force_sig_info(), but it seems to be really the wrong
> > > > call to use. force_sig_info() checks whether the program decided to
> > > > ignore or block the signal, and if it did, replaces the signal handler
> > > > with the default handler and unblocks the signal.
> > > >
> > > > Are you really suggesting that FP all FP signals should get this
> > > > treatment?
> > >
> > > feenableexcept(FE_OVERFLOW) kind of means "I can't run safely past
> > > an fp overflow exception, please signal me instead".
> > >
> > > If the process also blocked SIGFPE, that could be taken to mean
> > > "I can't run safely past an fp overflow exception _and_ I can't
> > > take SIGFPE either" ... i.e., if an fp overflow happens there is
> > > no way to proceed and it's really fatal.
> > >
> > > What SIG_IGN ought to mean is rather more debatable, but again,
> > > the process could be asking for two opposite things: guarantee a
> > > SIGFPE is delivered instead of running past an fp exception, and
> > > also guarantee that SIGFPE is _not_ delivered.
> > >
> > > It looks like arm and arm64 are different from most other arches
> > > (including x86) here, but I'm not sure what is considered correct, and
> > > it looks like the answer is not standardised. There's a possibility
> > > that some software goes subtly wrong on arm/arm64 where on other arches
> > > it would get terminated with SIGKILL.
> > >
> > > Whether this matters depends on how harmless the fp exception is to
> > > the work of the program. I think if an exception is set to trap
> > > via feenableexcept() then that's a strong hint the programmer thinks
> > > that exception is not harmless. OTOH, trapping is not always
> > > available anyway...
> >
> > Like many of these things, there is no clear answer. It's a set of
> > conflicting requirements, and as you point out, even if you've called
> > feenableexcept(), you are not guaranteed to get a trap.
> >
> > However, do remember that FP exceptions on ARM hardware are already
> > asynchronous - they get reported by the _next_ FP operation to the one
> > that caused them, which means they could be raised by a library function
> > sometime after it occured (when the library function decides to save the
> > FP registers to the stack before it makes use of them.) It's entirely
> > possible that the library function has blocked FP signals temporarily
> > (not explicitly, just decided to block all signals while it does
> > something sensitive) and will unblock them again afterwards - at which
> > point we get the SIGFPE, and it would be quite right to deliver that
> > signal to the user SIGFPE handler, rather than forcing it onto the
> > program mid-library function.
> >
> > It's also possible that SIGFPE could be blocked by another signal handler
> > having been invoked, and it triggers the latent generation of the SIGFPE.
> >
> > I'd be more inclined to agree with you if VFP exceptions were synchronous
> > but they aren't.
>
> Hmmm, it looks like imprecise fp exception traps are disallowed from
> ARMv8 onwards. I guess they made more sense when the FPU really was a
> coprocessor, or at least semidetached from the integer core.
>
> I think force_sig_info() makes sense here if and only if the traps
> are guaranteed to be precise, so we probably should use this on arm64.
> Not arm though (alpha doesn't either, if I understand the code
> correctly.)
>
> Does that make sense?
>
> Apparently, few recent cores (at least ARM's own ones) support fp
> exception trapping anyway... 1176 may be the most recent.

... and that makes the feenableexcept() argument about "A program
really wants to know" moot. It can enable the exceptions in the
FPSCR but its never going to receive a SIGFPE on CPUs that don't
do exception trapping.

--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

2018-01-17 16:12:46

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Wed, Jan 17, 2018 at 03:49:59PM +0000, Russell King - ARM Linux wrote:
> On Wed, Jan 17, 2018 at 03:37:31PM +0000, Dave Martin wrote:
> > On Wed, Jan 17, 2018 at 12:37:52PM +0000, Russell King - ARM Linux wrote:

[...]

> > > I'd be more inclined to agree with you if VFP exceptions were synchronous
> > > but they aren't.
> >
> > Hmmm, it looks like imprecise fp exception traps are disallowed from
> > ARMv8 onwards. I guess they made more sense when the FPU really was a
> > coprocessor, or at least semidetached from the integer core.
> >
> > I think force_sig_info() makes sense here if and only if the traps
> > are guaranteed to be precise, so we probably should use this on arm64.
> > Not arm though (alpha doesn't either, if I understand the code
> > correctly.)
> >
> > Does that make sense?
> >
> > Apparently, few recent cores (at least ARM's own ones) support fp
> > exception trapping anyway... 1176 may be the most recent.
>
> ... and that makes the feenableexcept() argument about "A program
> really wants to know" moot. It can enable the exceptions in the
> FPSCR but its never going to receive a SIGFPE on CPUs that don't
> do exception trapping.

Sort of. If the hardware doesn't support traps then those FP(S)CR
bits can't be set. feenableexcept() returns -1 if the requested
bits don't stick, but I'll bet there's software that doesn't bother
to check...

Relying on fp exception traps therefore isn't portable, but software
that does so can at least portably fail safe if it checks for the -1
return.

I'll cook up some RFC patches for arm64, then I could take a look at
arm is nobody else is working on it.

Cheers
---Dave

2018-01-17 16:46:40

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

Russell King - ARM Linux <[email protected]> writes:

> On Wed, Jan 17, 2018 at 12:15:05PM +0000, Dave Martin wrote:
>> On Wed, Jan 17, 2018 at 11:57:09AM +0000, Russell King - ARM Linux wrote:
>> > On Tue, Jan 16, 2018 at 04:28:50PM -0600, Eric W. Biederman wrote:
>> > > I will keep FPE_FIXME as a place holder until this gets sorted out.
>> > >
>> > > There is a second issue I am looking at in this location,
>> > > and maybe I don't have to address it now. But it looks like the code is
>> > > calling send_sig_info instead of force_sig_info for a synchronous
>> > > exception. Am I reading that correctly?
>> >
>> > VFP used to use force_sig_info(), but it seems to be really the wrong
>> > call to use. force_sig_info() checks whether the program decided to
>> > ignore or block the signal, and if it did, replaces the signal handler
>> > with the default handler and unblocks the signal.

That ignored and blocked behavior is a very weird implementation,
but for a synchronous signal it amounts to enforcing coredump and
then exit behavior. As the process does not continue past that
point the behavior is not observable by userspace.

>> > Are you really suggesting that FP all FP signals should get this
>> > treatment?

I am only suggesting that all synchronous signals, aka signals where
it helps to point at the instruction from the signal information
get that treatment. As the vast majority are synchronous I was
asking about this one oddball case.

>> feenableexcept(FE_OVERFLOW) kind of means "I can't run safely past
>> an fp overflow exception, please signal me instead".
>>
>> If the process also blocked SIGFPE, that could be taken to mean
>> "I can't run safely past an fp overflow exception _and_ I can't
>> take SIGFPE either" ... i.e., if an fp overflow happens there is
>> no way to proceed and it's really fatal.
>>
>> What SIG_IGN ought to mean is rather more debatable, but again,
>> the process could be asking for two opposite things: guarantee a
>> SIGFPE is delivered instead of running past an fp exception, and
>> also guarantee that SIGFPE is _not_ delivered.
>>
>> It looks like arm and arm64 are different from most other arches
>> (including x86) here, but I'm not sure what is considered correct, and
>> it looks like the answer is not standardised. There's a possibility
>> that some software goes subtly wrong on arm/arm64 where on other arches
>> it would get terminated with SIGKILL.

I looked it up yesterday to be clear, and POSIX actually says the
behavior is implemenation dependent/undefined if you try to ignore
SIGFPE.

>> Whether this matters depends on how harmless the fp exception is to
>> the work of the program. I think if an exception is set to trap
>> via feenableexcept() then that's a strong hint the programmer thinks
>> that exception is not harmless. OTOH, trapping is not always
>> available anyway...
>
> Like many of these things, there is no clear answer. It's a set of
> conflicting requirements, and as you point out, even if you've called
> feenableexcept(), you are not guaranteed to get a trap.
>
> However, do remember that FP exceptions on ARM hardware are already
> asynchronous - they get reported by the _next_ FP operation to the one
> that caused them, which means they could be raised by a library function
> sometime after it occured (when the library function decides to save the
> FP registers to the stack before it makes use of them.) It's entirely
> possible that the library function has blocked FP signals temporarily
> (not explicitly, just decided to block all signals while it does
> something sensitive) and will unblock them again afterwards - at which
> point we get the SIGFPE, and it would be quite right to deliver that
> signal to the user SIGFPE handler, rather than forcing it onto the
> program mid-library function.
>
> It's also possible that SIGFPE could be blocked by another signal handler
> having been invoked, and it triggers the latent generation of the SIGFPE.
>
> I'd be more inclined to agree with you if VFP exceptions were synchronous
> but they aren't.

From your description there still seems to be an association with an
instruction so I don't know if I would really call the signal
asynchronous. It sounds like the exception is delayed and not
asynchronous.

>> Was there some particular program being broken by the force_sig_info()
>> here?
>
> I don't recall.

> commit da41119af78864d27ccbf505949df788d5e8aaf5
> Author: Russell King <[email protected]>
> Date: Wed Jun 29 23:02:02 2005 +0100
>
> [PATCH] ARM: Don't force SIGFPE
>
> We were forcing SIGFPE on to a user program for no good reason.
> Use send_sig_info() instead.
>
> Signed-off-by: Russell King <[email protected]>

The commit looks like it was a case of the code not looking right
and you just switching to send_sig_info.

force_sig_info really out to be called something like synchronous_sig.

I am looking at sorting that out as part of cleaning up the signal
handling. There is currently a small bug where under the right
circumstances these synchronous signals might be improperly delivered
after a thread specific signal. To make that very unlikely there is a
special case in dequeue_signal for synchronous signals but it is
imperfect and slower than necessary.

The function really ought to look something like:

void synch_sig(struct siginfo *info)
{
struct task_struct *tsk = current;
int sig = info->si_signo;
struct ksignal ksig;
struct k_sigaction *ka;
bool blocked, ignored;
unsigned long flags;

WARN_ON(!siginmask(sig, SYNCHRONOUS_MASK));

copy_siginfo(info, &ksig.info);
spin_lock_irqsave(&tsk->sighand->siglock, flags);
ka = &tsk->sighand->action[sig - 1];
ignored = ka->sa.sa_handler == SIG_IGN;
blocked = sigismember(&tsk->blocked, sig);
ksig.ka = *ka;
if (blocked || ignored) {
ksig.ka.sa.sa_handler = SIG_DFL;
} else if (ka->sa.sa_flags & SA_ONESHOT) {
ka->sa.sa_handler = SIG_DFL;
}
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);

if (ksig.ka.sa.sa_handler == SIG_DFL) {
do_coredump(&ksig->info);
do_group_exit(sig);
/* NOTREACHED */
}

handle_signal(&ksig, signal_pt_regs());
}

Which is both clearer and faster and less buggy than the current
implementation as it delivers the signal immediately with no chance
of the signal queue to reorder things.

But it is going to take a little bit to get there as there are a number
of implementations of handle_signal like the ones on arm and arm64 that
perform needed register adjustments outside of handle_signal.

Eric





2018-01-17 17:17:06

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Wed, Jan 17, 2018 at 10:45:10AM -0600, Eric W. Biederman wrote:
> Russell King - ARM Linux <[email protected]> writes:
> >From your description there still seems to be an association with an
> instruction so I don't know if I would really call the signal
> asynchronous. It sounds like the exception is delayed and not
> asynchronous.

Traps can only be passed from ARM coprocessors by a coprocessor refusing
to execute an instruction. That's what happens in this case - the VFP
gets offered an instruction to execute. It accepts it, and the CPU
continues, leaving the VFP to execute its instruction independently. If
this instruction generates an error, then nothing happens at this point.

That error remains pending until the CPU offers the coprocessor the next
VFP instruction, which it refuses. That causes an undefined instruction
exception, and we trap into the kernel VFP code which reads the VFP
status and works out what needs to be done.

What this means is that if you execute a VFP instruction, wait 10 minutes
and then execute another VFP instruction, if the first VFP instruction
raised an exception, you'll get to hear about it 10 minutes later.

You can use whatever weasel words you want to describe that situation,
my choice is "asynchronous", your choice is "delayed". However, it is
clearly not "synchronous", and arguing that we should report something
synchronously that is not reported to _us_ synchronously (where
synchronous means "at the same time") is IMHO daft.

So, let's take an example:

installs SIGFPE handler
..fp instructions.. one of which raises an exception
returns to main loop
main loop blocks all signals while it sets stuff up
calls ppoll()

In the synchronous SIGFPE delivery case, the SIGFPE handler will be
called when the exception is generated in the FP code, and delivered
at that time. The fact that the main loop blocks all signals happens
later, so the users handler gets called as one expects.

In the VFP case, however, the FP instructions towards the end may not
end up causing the exception to be signalled until sometime later,
and as I've already explained, that may be the result of a C library
function accessing the VFP registers. This could well end up trying
to deliver the SIGFPE while signals are blocked, and we get
drastically different behaviour if force_sig_info() is used.

In the VFP case, if force_sig_info() is used, the program gets killed
at this point. In the non-VFP case, the program's signal handler was
called.

Using send_sig_info() results in the already delayed or asynchronous
signal being held off until ppoll() drops the blocking, at which point
the signal is delivered, the program handles it in its handler, and
the program continues to run.

So
1. non-VFP case, program doesn't get killed but gets the opportunity
to handle the signal.
2. VFP case with send_sig_info, program doesn't get killed but gets
the opportunity to handle the signal.
3. VFP case with force_sig_info, the program gets killed and dumps
core.

Which one of these results in a big change of behaviour in your
opinion?

--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

2018-01-17 17:18:16

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Mon, Jan 15, 2018 at 11:23:03AM -0600, Eric W. Biederman wrote:
> Dave Martin <[email protected]> writes:
>
> > On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:

[...]

> >> Possible ABI fixes include:
> >> - Send the signal without siginfo
> >> - Don't generate a signal

[...]

> >> - Possibly assign and use an appropriate si_code
> >> - Don't handle cases which can't happen
> >
> > I think a mixture of these two is the best approach.
> >
> > In any case, si_code == 0 here doesn't seem to have any explicit meaning.
> > I think we can translate all of the arm64 faults to proper si_codes --
> > see my sketch below. Probably means a bit more thought though.

[...]

> >> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c

[...]

> >> @@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
> >> }
> >>
> >> static const struct fault_info fault_info[] = {
> >> - { do_bad, SIGBUS, 0, "ttbr address size fault" },
> >> - { do_bad, SIGBUS, 0, "level 1 address size fault" },
> >> - { do_bad, SIGBUS, 0, "level 2 address size fault" },
> >> - { do_bad, SIGBUS, 0, "level 3 address size fault" },

If I convert this kind of thing to SIGKILL there really is nothing
sensible to put in si_code, except possibly SI_KERNEL (indicating that
the kill did not come from userspace). Even so, it hardly seems worth
filling in fields like si_pid and si_uid just to make this "correct".

In any case, if siginfo is never seen by userspace for SIGKILL this is
moot.

Obviously, siginfo is never copied to the user stack in that case, but
is it also guaranteed not to be visible to userspace by other means?
For ptrace I'm hoping not, since SIGKILL should nuke the tracee
immediately instead of being reported to the tracer as a
signal-delivery-stop -- so the tracer should get WIFSIGNALED() &&
WTERMSIG() == SIGKILL. A subsequent PTRACE_GETSIGINFO would fail with
ESRCH.

Does that match your understanding?

If so, there is some merit in not pretending to pass a reall value
for si_code.

Should si_code simply be ignored for the SIGKILL case?

Cheers
---Dave

2018-01-17 17:27:18

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

Dave Martin <[email protected]> writes:

> On Mon, Jan 15, 2018 at 11:23:03AM -0600, Eric W. Biederman wrote:
>> Dave Martin <[email protected]> writes:
>>
>> > On Thu, Jan 11, 2018 at 06:59:36PM -0600, Eric W. Biederman wrote:
>
> [...]
>
>> >> Possible ABI fixes include:
>> >> - Send the signal without siginfo
>> >> - Don't generate a signal
>
> [...]
>
>> >> - Possibly assign and use an appropriate si_code
>> >> - Don't handle cases which can't happen
>> >
>> > I think a mixture of these two is the best approach.
>> >
>> > In any case, si_code == 0 here doesn't seem to have any explicit meaning.
>> > I think we can translate all of the arm64 faults to proper si_codes --
>> > see my sketch below. Probably means a bit more thought though.
>
> [...]
>
>> >> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
>
> [...]
>
>> >> @@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
>> >> }
>> >>
>> >> static const struct fault_info fault_info[] = {
>> >> - { do_bad, SIGBUS, 0, "ttbr address size fault" },
>> >> - { do_bad, SIGBUS, 0, "level 1 address size fault" },
>> >> - { do_bad, SIGBUS, 0, "level 2 address size fault" },
>> >> - { do_bad, SIGBUS, 0, "level 3 address size fault" },
>
> If I convert this kind of thing to SIGKILL there really is nothing
> sensible to put in si_code, except possibly SI_KERNEL (indicating that
> the kill did not come from userspace). Even so, it hardly seems worth
> filling in fields like si_pid and si_uid just to make this "correct".
>
> In any case, if siginfo is never seen by userspace for SIGKILL this is
> moot.
>
> Obviously, siginfo is never copied to the user stack in that case, but
> is it also guaranteed not to be visible to userspace by other means?
> For ptrace I'm hoping not, since SIGKILL should nuke the tracee
> immediately instead of being reported to the tracer as a
> signal-delivery-stop -- so the tracer should get WIFSIGNALED() &&
> WTERMSIG() == SIGKILL. A subsequent PTRACE_GETSIGINFO would fail with
> ESRCH.
>
> Does that match your understanding?
>
> If so, there is some merit in not pretending to pass a reall value
> for si_code.
>
> Should si_code simply be ignored for the SIGKILL case?

I know what x86 does in a similar case is it uses force_sig instead of
force_sig_info. Then the generic code gets to worry about

If the appropriate paths generic paths get to worry about what siginfo
to fill in in that case. Which for SI_KERNEL is zero for everything
except the si_code and the si_signo.

That seems perfectly reasonable.

Eric

2018-01-17 17:41:05

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

On Wed, Jan 17, 2018 at 11:24:06AM -0600, Eric W. Biederman wrote:
> Dave Martin <[email protected]> writes:

[...]

> > Should si_code simply be ignored for the SIGKILL case?
>
> I know what x86 does in a similar case is it uses force_sig instead of
> force_sig_info. Then the generic code gets to worry about
>
> If the appropriate paths generic paths get to worry about what siginfo
> to fill in in that case. Which for SI_KERNEL is zero for everything
> except the si_code and the si_signo.
>
> That seems perfectly reasonable.

OK, I'll go with SI_KERNEL then.

Cheers
---Dave

2018-01-19 12:07:40

by Dave Martin

[permalink] [raw]
Subject: Re: [PATCH 08/11] signal/arm: Document conflicts with SI_USER and SIGFPE

On Mon, Jan 15, 2018 at 05:49:47PM +0000, Russell King - ARM Linux wrote:
> On Thu, Jan 11, 2018 at 06:59:37PM -0600, Eric W. Biederman wrote:
> > Setting si_code to 0 results in a userspace seeing an si_code of 0.
> > This is the same si_code as SI_USER. Posix and common sense requires
> > that SI_USER not be a signal specific si_code. As such this use of 0
> > for the si_code is a pretty horribly broken ABI.
> >
> > Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
> > value of __SI_KILL and now sees a value of SIL_KILL with the result
> > that uid and pid fields are copied and which might copying the si_addr
> > field by accident but certainly not by design. Making this a very
> > flakey implementation.
> >
> > Utilizing FPE_FIXME, siginfo_layout will now return SIL_FAULT and the
> > appropriate fields will be reliably copied.
>
> So what do you suggest when none of the SIGFPE FPE_xxx codes match the
> condition that "we don't know what happened" ? Raise a SIGKILL instead
> maybe? We will have dumped the VFP state into the kernel log at this
> point, things are pretty much fscked.
>
> It's probably an impossible condition unless the hardware has failed,
> no one has knowingly reported getting such a dump in their kernel log,
> so it's something that could very likely be changed in some way
> without anyone noticing.

Relating to this, what's your view on how to clean up the si_code zeros
in fsr-2level.c and fsr-3level.c?

Due to the historical evolution of the fault codes I'm less
confident of getting these right than for arm64.

Many are things that shouldn't happen and likely indicate a kernel bug
or system failure if they do, so at least some of the
{ do_bad, SIGxxx, 0, ... } entries can probably be changed to
{ do_bad, SIGKILL, SI_KERNEL, ... } with no ill effects. But there
are many fault codes whose meaning has changed over time.

Cheers
---Dave

2018-01-19 18:05:08

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH 22/22] signal: Unify and correct copy_siginfo_to_user32

On Mon, Jan 15, 2018 at 06:40:09PM -0600, Eric W. Biederman wrote:
> Among the existing architecture specific versions of
> copy_siginfo_to_user32 there are several different implementation
> problems. Some architectures fail to handle all of the cases in in
> the siginfo union. Some architectures perform a blind copy of the
> siginfo union when the si_code is negative. A blind copy suggests the
> data is expected to be in 32bit siginfo format, which means that
> receiving such a signal via signalfd won't work, or that the data is
> in 64bit siginfo and the code is copying nonsense to userspace.

Huh? Negative si_code comes from rt_sigqueueinfo(2); in that case
the sucker is supposed to pass user-supplied opaque chunk of data
in ->_sifields._pad. "Copy everything when ->si_code is negative"
is exactly the right behaviour. Failing to copy it out (and in, for
copy_siginfo_from_user32()) is a bug.

32bit tasks should behave on 64bit host like they would on 32bit one
when we have biarch compat. And "application using sigqueueinfo() to
pass data might be using different layouts of the payload" is not
an excuse for failing to transmit it in the first place.

2018-01-19 21:08:48

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 22/22] signal: Unify and correct copy_siginfo_to_user32

Al Viro <[email protected]> writes:

> On Mon, Jan 15, 2018 at 06:40:09PM -0600, Eric W. Biederman wrote:
>> Among the existing architecture specific versions of
>> copy_siginfo_to_user32 there are several different implementation
>> problems. Some architectures fail to handle all of the cases in in
>> the siginfo union. Some architectures perform a blind copy of the
>> siginfo union when the si_code is negative. A blind copy suggests the
>> data is expected to be in 32bit siginfo format, which means that
>> receiving such a signal via signalfd won't work, or that the data is
>> in 64bit siginfo and the code is copying nonsense to userspace.
>
> Huh? Negative si_code comes from rt_sigqueueinfo(2); in that case
> the sucker is supposed to pass user-supplied opaque chunk of data
> in ->_sifields._pad. "Copy everything when ->si_code is negative"
> is exactly the right behaviour. Failing to copy it out (and in, for
> copy_siginfo_from_user32()) is a bug.
>
> 32bit tasks should behave on 64bit host like they would on 32bit one
> when we have biarch compat. And "application using sigqueueinfo() to
> pass data might be using different layouts of the payload" is not
> an excuse for failing to transmit it in the first place.

If glibc actually offered rt_sigqueueinfo or any function that would
queue a full siginfo that would be a compelling argument.

As it is the only users of rt_sigqueueinfo that I am aware of
is CRIU and the implementation of sigqueue.

A couple of months ago I went hunting for users and for anyone who was
defining si_codes and I did not find a single instance of anything
defining signals that would pass more information than is known to
the kernel, and except for CRIU all I found was limited to what
you can do with sigqueue.

So no I do not think my choice will cause a regression.

Further SI_TIMER which the kernel does send is also negative. The
difference between negative and positive is that negative si_codes
are supposed to be signal agnostic and positive si_codes are signal
specific.

If this causes a single regression, or if anyone can point me at the
code of an application this will cause a regression for. I will
change the code right then and there.

My concern is that people have not been careful when defining new
signals. What looks like rules in one place are not the rules in
another place. If we had been careful struct siginfo would be the same
on both 32bit and 64bit, and in singalfd. As it is I am battling
accidental redefinitions of SI_USER by the kernel to be something else.

I think it is far more likley that someone will define a signal layout
that needs help going from 64bit to 32bit that my choice not copying all
of the bits will catch, rather than I will break some existing userspace
application. And if we catch it and the siginfo needs translation
because we are not commited to copying everything we can fix it.

Which is a long way of saying I think it would be gravely irresponsible
to just copy all of the bits of struct siginfo when si_code is negative.

Eric

2018-01-23 21:07:13

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 00/10] siginfo infrastructure


The following changes are available at:
git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git siginfo-testing

This updates the signal sending infrastructure to make it easier to get
to the point where we are certain every struct siginfo we send to
userspace is fully initialized and thus can be copied verbatim to
userspace.

Today copy_siginfo_to_user performs a piecewise copy of siginfo to
userspace because we don't know that all of the struct siginfo has
been initialized.

Unfortunately do to bugs not even knowing the proper union member is
enough to know that the fields we copy to userspace have all been
initialized in every case.

The core idiom that needs to be used is:

struct siginfo si;

clear_siginfo(&si);
si.xxx = yyy;
...
force_sig_info(SIG_sss, &si, tsk);

As the fields for the different union members all need to be initialized
this patchset works to make this less error prone by introducing a
series of helpers that take the needed fields and properly initialize
siginfo before sending it deeper into the signal stack.

The helpers are:
force_sig_fault
force_sig_mceerr
force_sig_bnderr
force_sig_pkuerr
send_sig_fault
send_sig_mceer

Today I count 227 calls of force_sig_info and send_sig_info in the
kernel. After the helpers introduced here are used in the obvious
places to use them the count shrinks to just 43. Something that is much
more reasonable to maintain and to audit to ensure all of the details
are just so.

This changeset does not include all of the architecture changes as that
is still a large set of changes that needs to be reviewed carefully.
I expect those to be post 4.17 material. While the infrastrcture
can go in in 4.16.

In addition to the helpers a several general cleanups happen to help
ensure that all instances of struct siginfo are intialized.

Eric W. Biederman (10):
ptrace: Use copy_siginfo in setsiginfo and getsiginfo
signal/arm64: Better isolate the COMPAT_TASK portion of ptrace_hbptriggered
signal: Don't use structure initializers for struct siginfo
signal: Replace memset(info,...) with clear_siginfo for clarity
signal: Add send_sig_fault and force_sig_fault
signal: Helpers for faults with specialized siginfo layouts
signal/powerpc: Remove unnecessary signal_code parameter of do_send_trap
signal/ptrace: Add force_sig_ptrace_errno_trap and use it where needed
mm/memory_failure: Remove unused trapno from memory_failure
signal/memory-failure: Use force_sig_mceerr and send_sig_mceerr

arch/arc/kernel/traps.c | 14 ++-
arch/arm/kernel/ptrace.c | 8 +-
arch/arm64/kernel/debug-monitors.c | 13 ++-
arch/arm64/kernel/ptrace.c | 42 +++----
arch/m68k/mm/fault.c | 3 +-
arch/mips/kernel/traps.c | 29 +++--
arch/parisc/kernel/pdt.c | 2 +-
arch/powerpc/include/asm/debug.h | 2 +-
arch/powerpc/kernel/process.c | 13 +--
arch/powerpc/kernel/traps.c | 12 +-
.../powerpc/platforms/powernv/opal-memory-errors.c | 2 +-
arch/tile/kernel/single_step.c | 24 ++--
arch/tile/kernel/traps.c | 4 +-
arch/tile/kernel/unaligned.c | 46 ++++----
arch/um/kernel/trap.c | 2 +-
arch/x86/kernel/cpu/mcheck/mce.c | 6 +-
arch/xtensa/kernel/ptrace.c | 8 +-
drivers/acpi/apei/ghes.c | 2 +-
drivers/base/memory.c | 2 +-
drivers/ras/cec.c | 2 +-
drivers/usb/core/devio.c | 4 +-
include/linux/mm.h | 4 +-
include/linux/sched/signal.h | 28 +++++
kernel/ptrace.c | 4 +-
kernel/seccomp.c | 2 +-
kernel/signal.c | 126 ++++++++++++++++++++-
kernel/time/posix-timers.c | 2 +-
mm/hwpoison-inject.c | 2 +-
mm/madvise.c | 2 +-
mm/memory-failure.c | 48 ++++----
30 files changed, 305 insertions(+), 153 deletions(-)

Eric

2018-01-23 21:10:14

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 01/10] ptrace: Use copy_siginfo in setsiginfo and getsiginfo

Now that copy_siginfo copies all of the fields this is safe, safer (as
all of the bits are guaranteed to be copied), clearer, and less error
prone than using a structure copy.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
kernel/ptrace.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index ec4365da9be8..f3c82e26b995 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -659,7 +659,7 @@ static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
if (lock_task_sighand(child, &flags)) {
error = -EINVAL;
if (likely(child->last_siginfo != NULL)) {
- *info = *child->last_siginfo;
+ copy_siginfo(info, child->last_siginfo);
error = 0;
}
unlock_task_sighand(child, &flags);
@@ -675,7 +675,7 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
if (lock_task_sighand(child, &flags)) {
error = -EINVAL;
if (likely(child->last_siginfo != NULL)) {
- *child->last_siginfo = *info;
+ copy_siginfo(child->last_siginfo, info);
error = 0;
}
unlock_task_sighand(child, &flags);
--
2.14.1


2018-01-23 21:10:18

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 09/10] mm/memory_failure: Remove unused trapno from memory_failure

Today 4 architectures set ARCH_SUPPORTS_MEMORY_FAILURE (arm64, parisc,
powerpc, and x86), while 4 other architectures set __ARCH_SI_TRAPNO
(alpha, metag, sparc, and tile). These two sets of architectures do
not interesect so remove the trapno paramater to remove confusion.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/parisc/kernel/pdt.c | 2 +-
.../powerpc/platforms/powernv/opal-memory-errors.c | 2 +-
arch/x86/kernel/cpu/mcheck/mce.c | 6 ++--
drivers/acpi/apei/ghes.c | 2 +-
drivers/base/memory.c | 2 +-
drivers/ras/cec.c | 2 +-
include/linux/mm.h | 4 +--
mm/hwpoison-inject.c | 2 +-
mm/madvise.c | 2 +-
mm/memory-failure.c | 33 +++++++++-------------
10 files changed, 25 insertions(+), 32 deletions(-)

diff --git a/arch/parisc/kernel/pdt.c b/arch/parisc/kernel/pdt.c
index e07eb34c8750..36434d4da381 100644
--- a/arch/parisc/kernel/pdt.c
+++ b/arch/parisc/kernel/pdt.c
@@ -325,7 +325,7 @@ static int pdt_mainloop(void *unused)
#ifdef CONFIG_MEMORY_FAILURE
if ((pde & PDT_ADDR_PERM_ERR) ||
((pde & PDT_ADDR_SINGLE_ERR) == 0))
- memory_failure(pde >> PAGE_SHIFT, 0, 0);
+ memory_failure(pde >> PAGE_SHIFT, 0);
else
soft_offline_page(
pfn_to_page(pde >> PAGE_SHIFT), 0);
diff --git a/arch/powerpc/platforms/powernv/opal-memory-errors.c b/arch/powerpc/platforms/powernv/opal-memory-errors.c
index d9916ea62305..8ddc1accf199 100644
--- a/arch/powerpc/platforms/powernv/opal-memory-errors.c
+++ b/arch/powerpc/platforms/powernv/opal-memory-errors.c
@@ -60,7 +60,7 @@ static void handle_memory_error_event(struct OpalMemoryErrorData *merr_evt)
}

for (; paddr_start < paddr_end; paddr_start += PAGE_SIZE) {
- memory_failure(paddr_start >> PAGE_SHIFT, 0, 0);
+ memory_failure(paddr_start >> PAGE_SHIFT, 0);
}
}

diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index b1d616d08eee..3b7319e25168 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -582,7 +582,7 @@ static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,

if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) {
pfn = mce->addr >> PAGE_SHIFT;
- memory_failure(pfn, MCE_VECTOR, 0);
+ memory_failure(pfn, 0);
}

return NOTIFY_OK;
@@ -1046,7 +1046,7 @@ static int do_memory_failure(struct mce *m)
pr_err("Uncorrected hardware memory error in user-access at %llx", m->addr);
if (!(m->mcgstatus & MCG_STATUS_RIPV))
flags |= MF_MUST_KILL;
- ret = memory_failure(m->addr >> PAGE_SHIFT, MCE_VECTOR, flags);
+ ret = memory_failure(m->addr >> PAGE_SHIFT, flags);
if (ret)
pr_err("Memory error not recovered");
return ret;
@@ -1325,7 +1325,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
EXPORT_SYMBOL_GPL(do_machine_check);

#ifndef CONFIG_MEMORY_FAILURE
-int memory_failure(unsigned long pfn, int vector, int flags)
+int memory_failure(unsigned long pfn, int flags)
{
/* mce_severity() should not hand us an ACTION_REQUIRED error */
BUG_ON(flags & MF_ACTION_REQUIRED);
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 6402f7fad3bb..bb5f9c643e0e 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -410,7 +410,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
flags = 0;

if (flags != -1)
- memory_failure_queue(pfn, 0, flags);
+ memory_failure_queue(pfn, flags);
#endif
}

diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 1d60b58a8c19..fe4b24f05f6a 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -569,7 +569,7 @@ store_hard_offline_page(struct device *dev,
if (kstrtoull(buf, 0, &pfn) < 0)
return -EINVAL;
pfn >>= PAGE_SHIFT;
- ret = memory_failure(pfn, 0, 0);
+ ret = memory_failure(pfn, 0);
return ret ? ret : count;
}

diff --git a/drivers/ras/cec.c b/drivers/ras/cec.c
index ca44e6977cf2..2d9ec378a8bc 100644
--- a/drivers/ras/cec.c
+++ b/drivers/ras/cec.c
@@ -327,7 +327,7 @@ int cec_add_elem(u64 pfn)
} else {
/* We have reached max count for this page, soft-offline it. */
pr_err("Soft-offlining pfn: 0x%llx\n", pfn);
- memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE);
+ memory_failure_queue(pfn, MF_SOFT_OFFLINE);
ca->pfns_poisoned++;
}

diff --git a/include/linux/mm.h b/include/linux/mm.h
index ea818ff739cd..7fc92384977e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2570,8 +2570,8 @@ enum mf_flags {
MF_MUST_KILL = 1 << 2,
MF_SOFT_OFFLINE = 1 << 3,
};
-extern int memory_failure(unsigned long pfn, int trapno, int flags);
-extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
+extern int memory_failure(unsigned long pfn, int flags);
+extern void memory_failure_queue(unsigned long pfn, int flags);
extern int unpoison_memory(unsigned long pfn);
extern int get_hwpoison_page(struct page *page);
#define put_hwpoison_page(page) put_page(page)
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index 356df057a2a8..b6ac70616c32 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -52,7 +52,7 @@ static int hwpoison_inject(void *data, u64 val)

inject:
pr_info("Injecting memory failure at pfn %#lx\n", pfn);
- return memory_failure(pfn, 18, MF_COUNT_INCREASED);
+ return memory_failure(pfn, MF_COUNT_INCREASED);
put_out:
put_hwpoison_page(p);
return 0;
diff --git a/mm/madvise.c b/mm/madvise.c
index 751e97aa2210..4d3c922ea1a1 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -661,7 +661,7 @@ static int madvise_inject_error(int behavior,
pr_info("Injecting memory failure for pfn %#lx at process virtual address %#lx\n",
page_to_pfn(page), start);

- ret = memory_failure(page_to_pfn(page), 0, MF_COUNT_INCREASED);
+ ret = memory_failure(page_to_pfn(page), MF_COUNT_INCREASED);
if (ret)
return ret;
}
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 4acdf393a801..c5f5f31bd979 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -178,7 +178,7 @@ EXPORT_SYMBOL_GPL(hwpoison_filter);
* ``action optional'' if they are not immediately affected by the error
* ``action required'' if error happened in current execution context
*/
-static int kill_proc(struct task_struct *t, unsigned long addr, int trapno,
+static int kill_proc(struct task_struct *t, unsigned long addr,
unsigned long pfn, struct page *page, int flags)
{
struct siginfo si;
@@ -189,9 +189,6 @@ static int kill_proc(struct task_struct *t, unsigned long addr, int trapno,
si.si_signo = SIGBUS;
si.si_errno = 0;
si.si_addr = (void *)addr;
-#ifdef __ARCH_SI_TRAPNO
- si.si_trapno = trapno;
-#endif
si.si_addr_lsb = compound_order(compound_head(page)) + PAGE_SHIFT;

if ((flags & MF_ACTION_REQUIRED) && t->mm == current->mm) {
@@ -323,7 +320,7 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,
* Also when FAIL is set do a force kill because something went
* wrong earlier.
*/
-static void kill_procs(struct list_head *to_kill, int forcekill, int trapno,
+static void kill_procs(struct list_head *to_kill, int forcekill,
bool fail, struct page *page, unsigned long pfn,
int flags)
{
@@ -348,7 +345,7 @@ static void kill_procs(struct list_head *to_kill, int forcekill, int trapno,
* check for that, but we need to tell the
* process anyways.
*/
- else if (kill_proc(tk->tsk, tk->addr, trapno,
+ else if (kill_proc(tk->tsk, tk->addr,
pfn, page, flags) < 0)
pr_err("Memory failure: %#lx: Cannot send advisory machine check signal to %s:%d\n",
pfn, tk->tsk->comm, tk->tsk->pid);
@@ -927,7 +924,7 @@ EXPORT_SYMBOL_GPL(get_hwpoison_page);
* the pages and send SIGBUS to the processes if the data was dirty.
*/
static bool hwpoison_user_mappings(struct page *p, unsigned long pfn,
- int trapno, int flags, struct page **hpagep)
+ int flags, struct page **hpagep)
{
enum ttu_flags ttu = TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS;
struct address_space *mapping;
@@ -1017,7 +1014,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn,
* any accesses to the poisoned memory.
*/
forcekill = PageDirty(hpage) || (flags & MF_MUST_KILL);
- kill_procs(&tokill, forcekill, trapno, !unmap_success, p, pfn, flags);
+ kill_procs(&tokill, forcekill, !unmap_success, p, pfn, flags);

return unmap_success;
}
@@ -1045,7 +1042,7 @@ static int identify_page_state(unsigned long pfn, struct page *p,
return page_action(ps, p, pfn);
}

-static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)
+static int memory_failure_hugetlb(unsigned long pfn, int flags)
{
struct page *p = pfn_to_page(pfn);
struct page *head = compound_head(p);
@@ -1090,7 +1087,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)
return 0;
}

- if (!hwpoison_user_mappings(p, pfn, trapno, flags, &head)) {
+ if (!hwpoison_user_mappings(p, pfn, flags, &head)) {
action_result(pfn, MF_MSG_UNMAP_FAILED, MF_IGNORED);
res = -EBUSY;
goto out;
@@ -1105,7 +1102,6 @@ static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)
/**
* memory_failure - Handle memory failure of a page.
* @pfn: Page Number of the corrupted page
- * @trapno: Trap number reported in the signal to user space.
* @flags: fine tune action taken
*
* This function is called by the low level machine check code
@@ -1120,7 +1116,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int trapno, int flags)
* Must run in process context (e.g. a work queue) with interrupts
* enabled and no spinlocks hold.
*/
-int memory_failure(unsigned long pfn, int trapno, int flags)
+int memory_failure(unsigned long pfn, int flags)
{
struct page *p;
struct page *hpage;
@@ -1129,7 +1125,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
unsigned long page_flags;

if (!sysctl_memory_failure_recovery)
- panic("Memory failure from trap %d on page %lx", trapno, pfn);
+ panic("Memory failure on page %lx", pfn);

if (!pfn_valid(pfn)) {
pr_err("Memory failure: %#lx: memory outside kernel control\n",
@@ -1139,7 +1135,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)

p = pfn_to_page(pfn);
if (PageHuge(p))
- return memory_failure_hugetlb(pfn, trapno, flags);
+ return memory_failure_hugetlb(pfn, flags);
if (TestSetPageHWPoison(p)) {
pr_err("Memory failure: %#lx: already hardware poisoned\n",
pfn);
@@ -1268,7 +1264,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
* When the raw error page is thp tail page, hpage points to the raw
* page after thp split.
*/
- if (!hwpoison_user_mappings(p, pfn, trapno, flags, &hpage)) {
+ if (!hwpoison_user_mappings(p, pfn, flags, &hpage)) {
action_result(pfn, MF_MSG_UNMAP_FAILED, MF_IGNORED);
res = -EBUSY;
goto out;
@@ -1296,7 +1292,6 @@ EXPORT_SYMBOL_GPL(memory_failure);

struct memory_failure_entry {
unsigned long pfn;
- int trapno;
int flags;
};

@@ -1312,7 +1307,6 @@ static DEFINE_PER_CPU(struct memory_failure_cpu, memory_failure_cpu);
/**
* memory_failure_queue - Schedule handling memory failure of a page.
* @pfn: Page Number of the corrupted page
- * @trapno: Trap number reported in the signal to user space.
* @flags: Flags for memory failure handling
*
* This function is called by the low level hardware error handler
@@ -1326,13 +1320,12 @@ static DEFINE_PER_CPU(struct memory_failure_cpu, memory_failure_cpu);
*
* Can run in IRQ context.
*/
-void memory_failure_queue(unsigned long pfn, int trapno, int flags)
+void memory_failure_queue(unsigned long pfn, int flags)
{
struct memory_failure_cpu *mf_cpu;
unsigned long proc_flags;
struct memory_failure_entry entry = {
.pfn = pfn,
- .trapno = trapno,
.flags = flags,
};

@@ -1365,7 +1358,7 @@ static void memory_failure_work_func(struct work_struct *work)
if (entry.flags & MF_SOFT_OFFLINE)
soft_offline_page(pfn_to_page(entry.pfn), entry.flags);
else
- memory_failure(entry.pfn, entry.trapno, entry.flags);
+ memory_failure(entry.pfn, entry.flags);
}
}

--
2.14.1


2018-01-23 21:10:33

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 07/10] signal/powerpc: Remove unnecessary signal_code parameter of do_send_trap

signal_code is always TRAP_HWBKPT

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/powerpc/include/asm/debug.h | 2 +-
arch/powerpc/kernel/process.c | 6 +++---
arch/powerpc/kernel/traps.c | 12 ++++++------
3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h
index 14e71ff6579e..fc97404de0a3 100644
--- a/arch/powerpc/include/asm/debug.h
+++ b/arch/powerpc/include/asm/debug.h
@@ -49,7 +49,7 @@ void set_breakpoint(struct arch_hw_breakpoint *brk);
void __set_breakpoint(struct arch_hw_breakpoint *brk);
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
extern void do_send_trap(struct pt_regs *regs, unsigned long address,
- unsigned long error_code, int signal_code, int brkpt);
+ unsigned long error_code, int brkpt);
#else

extern void do_break(struct pt_regs *regs, unsigned long address,
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 72be0c32e902..bfb48cf56bc3 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -601,11 +601,11 @@ EXPORT_SYMBOL(flush_all_to_thread);

#ifdef CONFIG_PPC_ADV_DEBUG_REGS
void do_send_trap(struct pt_regs *regs, unsigned long address,
- unsigned long error_code, int signal_code, int breakpt)
+ unsigned long error_code, int breakpt)
{
siginfo_t info;

- current->thread.trap_nr = signal_code;
+ current->thread.trap_nr = TRAP_HWBKPT;
if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
return;
@@ -613,7 +613,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,
/* Deliver the signal to userspace */
info.si_signo = SIGTRAP;
info.si_errno = breakpt; /* breakpoint or watchpoint id */
- info.si_code = signal_code;
+ info.si_code = TRAP_HWBKPT;
info.si_addr = (void __user *)address;
force_sig_info(SIGTRAP, &info, current);
}
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index f2e6e1838952..c93f1e6a9fff 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1750,34 +1750,34 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
current->thread.debug.dbcr2 &= ~DBCR2_DAC12MODE;
#endif
- do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT,
+ do_send_trap(regs, mfspr(SPRN_DAC1), debug_status,
5);
changed |= 0x01;
} else if (debug_status & (DBSR_DAC2R | DBSR_DAC2W)) {
dbcr_dac(current) &= ~(DBCR_DAC2R | DBCR_DAC2W);
- do_send_trap(regs, mfspr(SPRN_DAC2), debug_status, TRAP_HWBKPT,
+ do_send_trap(regs, mfspr(SPRN_DAC2), debug_status,
6);
changed |= 0x01;
} else if (debug_status & DBSR_IAC1) {
current->thread.debug.dbcr0 &= ~DBCR0_IAC1;
dbcr_iac_range(current) &= ~DBCR_IAC12MODE;
- do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT,
+ do_send_trap(regs, mfspr(SPRN_IAC1), debug_status,
1);
changed |= 0x01;
} else if (debug_status & DBSR_IAC2) {
current->thread.debug.dbcr0 &= ~DBCR0_IAC2;
- do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT,
+ do_send_trap(regs, mfspr(SPRN_IAC2), debug_status,
2);
changed |= 0x01;
} else if (debug_status & DBSR_IAC3) {
current->thread.debug.dbcr0 &= ~DBCR0_IAC3;
dbcr_iac_range(current) &= ~DBCR_IAC34MODE;
- do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT,
+ do_send_trap(regs, mfspr(SPRN_IAC3), debug_status,
3);
changed |= 0x01;
} else if (debug_status & DBSR_IAC4) {
current->thread.debug.dbcr0 &= ~DBCR0_IAC4;
- do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT,
+ do_send_trap(regs, mfspr(SPRN_IAC4), debug_status,
4);
changed |= 0x01;
}
--
2.14.1


2018-01-23 21:10:35

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 10/10] signal/memory-failure: Use force_sig_mceerr and send_sig_mceerr

Delegate filling out struct siginfo to functions in kernel/signal.c
to simplify the code.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
mm/memory-failure.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index c5f5f31bd979..4b80ccee4535 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -181,19 +181,16 @@ EXPORT_SYMBOL_GPL(hwpoison_filter);
static int kill_proc(struct task_struct *t, unsigned long addr,
unsigned long pfn, struct page *page, int flags)
{
- struct siginfo si;
+ short addr_lsb;
int ret;

pr_err("Memory failure: %#lx: Killing %s:%d due to hardware memory corruption\n",
pfn, t->comm, t->pid);
- si.si_signo = SIGBUS;
- si.si_errno = 0;
- si.si_addr = (void *)addr;
- si.si_addr_lsb = compound_order(compound_head(page)) + PAGE_SHIFT;
+ addr_lsb = compound_order(compound_head(page)) + PAGE_SHIFT;

if ((flags & MF_ACTION_REQUIRED) && t->mm == current->mm) {
- si.si_code = BUS_MCEERR_AR;
- ret = force_sig_info(SIGBUS, &si, current);
+ ret = force_sig_mceerr(BUS_MCEERR_AR, (void __user *)addr,
+ addr_lsb, current);
} else {
/*
* Don't use force here, it's convenient if the signal
@@ -201,8 +198,8 @@ static int kill_proc(struct task_struct *t, unsigned long addr,
* This could cause a loop when the user sets SIGBUS
* to SIG_IGN, but hopefully no one will do that?
*/
- si.si_code = BUS_MCEERR_AO;
- ret = send_sig_info(SIGBUS, &si, t); /* synchronous? */
+ ret = send_sig_mceerr(BUS_MCEERR_AO, (void __user *)addr,
+ addr_lsb, t); /* synchronous? */
}
if (ret < 0)
pr_info("Memory failure: Error sending signal to %s:%d: %d\n",
--
2.14.1


2018-01-23 21:11:01

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 05/10] signal: Add send_sig_fault and force_sig_fault

The vast majority of signals sent from architecture specific code are
simple faults. Encapsulate this reality with two helper functions so
that the nit-picky implementation of preparing a siginfo does not need
to be repeated many times on each architecture.

As only some architectures support the trapno field, make the trapno
arguement only present on those architectures.

Similary as ia64 has three fields: imm, flags, and isr that
are specific to it. Have those arguments always present on ia64
and no where else.

This ensures the architecture specific code always remembers which
fields it needs to pass into the siginfo structure.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/linux/sched/signal.h | 20 +++++++++++++++++++
kernel/signal.c | 47 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)

diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 0aa4548fb492..375f31eb3b6b 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -285,6 +285,26 @@ static inline void kernel_signal_stop(void)

schedule();
}
+#ifdef __ARCH_SI_TRAPNO
+# define ___ARCH_SI_TRAPNO(_a1) , _a1
+#else
+# define ___ARCH_SI_TRAPNO(_a1)
+#endif
+#ifdef __ia64__
+# define ___ARCH_SI_IA64(_a1, _a2, _a3) , _a1, _a2, _a3
+#else
+# define ___ARCH_SI_IA64(_a1, _a2, _a3)
+#endif
+
+int force_sig_fault(int sig, int code, void __user *addr
+ ___ARCH_SI_TRAPNO(int trapno)
+ ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
+ , struct task_struct *t);
+int send_sig_fault(int sig, int code, void __user *addr
+ ___ARCH_SI_TRAPNO(int trapno)
+ ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
+ , struct task_struct *t);
+
extern int send_sig_info(int, struct siginfo *, struct task_struct *);
extern int force_sigsegv(int, struct task_struct *);
extern int force_sig_info(int, struct siginfo *, struct task_struct *);
diff --git a/kernel/signal.c b/kernel/signal.c
index f14492ff976f..15ec7b3cbe69 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1491,6 +1491,53 @@ force_sigsegv(int sig, struct task_struct *p)
return 0;
}

+int force_sig_fault(int sig, int code, void __user *addr
+ ___ARCH_SI_TRAPNO(int trapno)
+ ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
+ , struct task_struct *t)
+{
+ struct siginfo info;
+
+ clear_siginfo(&info);
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+#ifdef __ARCH_SI_TRAPNO
+ info.si_trapno = trapno;
+#endif
+#ifdef __ia64__
+ info.si_imm = imm;
+ info.si_flags = flags;
+ info.si_isr = isr;
+#endif
+ return force_sig_info(info.si_signo, &info, t);
+}
+
+int send_sig_fault(int sig, int code, void __user *addr
+ ___ARCH_SI_TRAPNO(int trapno)
+ ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
+ , struct task_struct *t)
+{
+ struct siginfo info;
+
+ clear_siginfo(&info);
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+#ifdef __ARCH_SI_TRAPNO
+ info.si_trapno = trapno;
+#endif
+#ifdef __ia64__
+ info.si_imm = imm;
+ info.si_flags = flags;
+ info.si_isr = isr;
+#endif
+ return send_sig_info(info.si_signo, &info, t);
+}
+
+
int kill_pgrp(struct pid *pid, int sig, int priv)
{
int ret;
--
2.14.1


2018-01-23 21:11:09

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 06/10] signal: Helpers for faults with specialized siginfo layouts

The helpers added are:
send_sig_mceerr
force_sig_mceerr
force_sig_bnderr
force_sig_pkuerr

Filling out siginfo properly can ge tricky. Especially for these
specialized cases where the temptation is to share code with other
cases which use a different subset of siginfo fields. Unfortunately
that code sharing frequently results in bugs with the wrong siginfo
fields filled in, and makes it harder to verify that the siginfo
structure was properly initialized.

Provide these helpers instead that get all of the details right, and
guarantee that siginfo is properly initialized.

send_sig_mceerr and force_sig_mceer are a little special as two si
codes BUS_MCEERR_AO and BUS_MCEER_AR both use the same extended
signinfo layout.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
include/linux/sched/signal.h | 6 +++++
kernel/signal.c | 61 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)

diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 375f31eb3b6b..944fe6356f4a 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -305,6 +305,12 @@ int send_sig_fault(int sig, int code, void __user *addr
___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
, struct task_struct *t);

+int force_sig_mceerr(int code, void __user *, short, struct task_struct *);
+int send_sig_mceerr(int code, void __user *, short, struct task_struct *);
+
+int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper);
+int force_sig_pkuerr(void __user *addr, u32 pkey);
+
extern int send_sig_info(int, struct siginfo *, struct task_struct *);
extern int force_sigsegv(int, struct task_struct *);
extern int force_sig_info(int, struct siginfo *, struct task_struct *);
diff --git a/kernel/signal.c b/kernel/signal.c
index 15ec7b3cbe69..4f6300ef8062 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1537,6 +1537,67 @@ int send_sig_fault(int sig, int code, void __user *addr
return send_sig_info(info.si_signo, &info, t);
}

+#if defined(BUS_MCEERR_AO) && defined(BUS_MCEERR_AR)
+int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
+{
+ struct siginfo info;
+
+ WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
+ clear_siginfo(&info);
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+ info.si_addr_lsb = lsb;
+ return force_sig_info(info.si_signo, &info, t);
+}
+
+int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
+{
+ struct siginfo info;
+
+ WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
+ clear_siginfo(&info);
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = addr;
+ info.si_addr_lsb = lsb;
+ return send_sig_info(info.si_signo, &info, t);
+}
+EXPORT_SYMBOL(send_sig_mceerr);
+#endif
+
+#ifdef SEGV_BNDERR
+int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)
+{
+ struct siginfo info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_BNDERR;
+ info.si_addr = addr;
+ info.si_lower = lower;
+ info.si_upper = upper;
+ return force_sig_info(info.si_signo, &info, current);
+}
+#endif
+
+#ifdef SEGV_PKUERR
+int force_sig_pkuerr(void __user *addr, u32 pkey)
+{
+ struct siginfo info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_PKUERR;
+ info.si_addr = addr;
+ info.si_pkey = pkey;
+ return force_sig_info(info.si_signo, &info, current);
+}
+#endif

int kill_pgrp(struct pid *pid, int sig, int priv)
{
--
2.14.1


2018-01-23 21:11:20

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 08/10] signal/ptrace: Add force_sig_ptrace_errno_trap and use it where needed

There are so many places that build struct siginfo by hand that at
least one of them is bound to get it wrong. A handful of cases in the
kernel arguably did just that when using the errno field of siginfo to
pass no errno values to userspace. The usage is limited to a single
si_code so at least does not mess up anything else.

Encapsulate this questionable pattern in a helper function so
that the userspace ABI is preserved.

Update all of the places that use this pattern to use the new helper
function.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arm/kernel/ptrace.c | 8 +-------
arch/arm64/kernel/ptrace.c | 6 ++++--
arch/powerpc/kernel/process.c | 9 ++-------
arch/xtensa/kernel/ptrace.c | 8 +-------
include/linux/sched/signal.h | 2 ++
kernel/signal.c | 15 +++++++++++++++
6 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 58e3771e4c5b..7724b0f661b3 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -390,7 +390,6 @@ static void ptrace_hbptriggered(struct perf_event *bp,
struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
long num;
int i;
- siginfo_t info;

for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i)
if (current->thread.debug.hbp[i] == bp)
@@ -398,12 +397,7 @@ static void ptrace_hbptriggered(struct perf_event *bp,

num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i);

- info.si_signo = SIGTRAP;
- info.si_errno = (int)num;
- info.si_code = TRAP_HWBKPT;
- info.si_addr = (void __user *)(bkpt->trigger);
-
- force_sig_info(SIGTRAP, &info, current);
+ force_sig_ptrace_errno_trap((int)num, (void __user *)(bkpt->trigger));
}

/*
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 95daa1478a7c..6618036ae6d4 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -190,21 +190,23 @@ static void ptrace_hbptriggered(struct perf_event *bp,

#ifdef CONFIG_COMPAT
if (is_compat_task()) {
+ int si_errno = 0;
int i;

for (i = 0; i < ARM_MAX_BRP; ++i) {
if (current->thread.debug.hbp_break[i] == bp) {
- info.si_errno = (i << 1) + 1;
+ si_errno = (i << 1) + 1;
break;
}
}

for (i = 0; i < ARM_MAX_WRP; ++i) {
if (current->thread.debug.hbp_watch[i] == bp) {
- info.si_errno = -((i << 1) + 1);
+ si_errno = -((i << 1) + 1);
break;
}
}
+ force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger);
}
#endif
force_sig_info(SIGTRAP, &info, current);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index bfb48cf56bc3..4208cbe2fb7f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -603,19 +603,14 @@ EXPORT_SYMBOL(flush_all_to_thread);
void do_send_trap(struct pt_regs *regs, unsigned long address,
unsigned long error_code, int breakpt)
{
- siginfo_t info;
-
current->thread.trap_nr = TRAP_HWBKPT;
if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
return;

/* Deliver the signal to userspace */
- info.si_signo = SIGTRAP;
- info.si_errno = breakpt; /* breakpoint or watchpoint id */
- info.si_code = TRAP_HWBKPT;
- info.si_addr = (void __user *)address;
- force_sig_info(SIGTRAP, &info, current);
+ force_sig_ptrace_errno_trap(breakpt, /* breakpoint or watchpoint id */
+ (void __user *)address);
}
#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
void do_break (struct pt_regs *regs, unsigned long address,
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index e2461968efb2..c0845cb1cbb9 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -278,7 +278,6 @@ static void ptrace_hbptriggered(struct perf_event *bp,
struct pt_regs *regs)
{
int i;
- siginfo_t info;
struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);

if (bp->attr.bp_type & HW_BREAKPOINT_X) {
@@ -293,12 +292,7 @@ static void ptrace_hbptriggered(struct perf_event *bp,
i = (i << 1) | 1;
}

- info.si_signo = SIGTRAP;
- info.si_errno = i;
- info.si_code = TRAP_HWBKPT;
- info.si_addr = (void __user *)bkpt->address;
-
- force_sig_info(SIGTRAP, &info, current);
+ force_sig_ptrace_errno_trap(i, (void __user *)bkpt->address);
}

static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index 944fe6356f4a..23b4f9cb82db 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -311,6 +311,8 @@ int send_sig_mceerr(int code, void __user *, short, struct task_struct *);
int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper);
int force_sig_pkuerr(void __user *addr, u32 pkey);

+int force_sig_ptrace_errno_trap(int errno, void __user *addr);
+
extern int send_sig_info(int, struct siginfo *, struct task_struct *);
extern int force_sigsegv(int, struct task_struct *);
extern int force_sig_info(int, struct siginfo *, struct task_struct *);
diff --git a/kernel/signal.c b/kernel/signal.c
index 4f6300ef8062..e549174c0831 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1599,6 +1599,21 @@ int force_sig_pkuerr(void __user *addr, u32 pkey)
}
#endif

+/* For the crazy architectures that include trap information in
+ * the errno field, instead of an actual errno value.
+ */
+int force_sig_ptrace_errno_trap(int errno, void __user *addr)
+{
+ struct siginfo info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGTRAP;
+ info.si_errno = errno;
+ info.si_code = TRAP_HWBKPT;
+ info.si_addr = addr;
+ return force_sig_info(info.si_signo, &info, current);
+}
+
int kill_pgrp(struct pid *pid, int sig, int priv)
{
int ret;
--
2.14.1


2018-01-23 21:11:48

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 03/10] signal: Don't use structure initializers for struct siginfo

The siginfo structure has all manners of holes with the result that a
structure initializer is not guaranteed to initialize all of the bits.
As we have to copy the structure to userspace don't even try to use
a structure initializer. Instead use clear_siginfo followed by initializing
selected fields. This gives a guarantee that uninitialized kernel memory
is not copied to userspace.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arc/kernel/traps.c | 14 +++++++-----
arch/arm64/kernel/debug-monitors.c | 13 ++++++-----
arch/arm64/kernel/ptrace.c | 13 ++++++-----
arch/m68k/mm/fault.c | 3 ++-
arch/mips/kernel/traps.c | 29 ++++++++++++++++--------
arch/tile/kernel/single_step.c | 24 +++++++++++---------
arch/tile/kernel/traps.c | 4 +++-
arch/tile/kernel/unaligned.c | 46 +++++++++++++++++++++-----------------
kernel/signal.c | 3 ++-
9 files changed, 89 insertions(+), 60 deletions(-)

diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c
index bcd7c9fc5d0f..c7206789e9ce 100644
--- a/arch/arc/kernel/traps.c
+++ b/arch/arc/kernel/traps.c
@@ -65,12 +65,14 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info)
#define DO_ERROR_INFO(signr, str, name, sicode) \
int name(unsigned long address, struct pt_regs *regs) \
{ \
- siginfo_t info = { \
- .si_signo = signr, \
- .si_errno = 0, \
- .si_code = sicode, \
- .si_addr = (void __user *)address, \
- }; \
+ siginfo_t info; \
+ \
+ clear_siginfo(&info); \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = (void __user *)address; \
+ \
return unhandled_exception(str, regs, &info);\
}

diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index a88b6ccebbb4..53781f5687c5 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -209,12 +209,13 @@ NOKPROBE_SYMBOL(call_step_hook);
static void send_user_sigtrap(int si_code)
{
struct pt_regs *regs = current_pt_regs();
- siginfo_t info = {
- .si_signo = SIGTRAP,
- .si_errno = 0,
- .si_code = si_code,
- .si_addr = (void __user *)instruction_pointer(regs),
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = si_code;
+ info.si_addr = (void __user *)instruction_pointer(regs);

if (WARN_ON(!user_mode(regs)))
return;
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 0a1cf830e4b3..95daa1478a7c 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -180,12 +180,13 @@ static void ptrace_hbptriggered(struct perf_event *bp,
struct pt_regs *regs)
{
struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
- siginfo_t info = {
- .si_signo = SIGTRAP,
- .si_errno = 0,
- .si_code = TRAP_HWBKPT,
- .si_addr = (void __user *)(bkpt->trigger),
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_HWBKPT;
+ info.si_addr = (void __user *)(bkpt->trigger);

#ifdef CONFIG_COMPAT
if (is_compat_task()) {
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index 127d7c1f2090..03253c4f8e6a 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -21,8 +21,9 @@ extern void die_if_kernel(char *, struct pt_regs *, long);

int send_fault_sig(struct pt_regs *regs)
{
- siginfo_t siginfo = { 0, 0, 0, };
+ siginfo_t siginfo;

+ clear_siginfo(&siginfo);
siginfo.si_signo = current->thread.signo;
siginfo.si_code = current->thread.code;
siginfo.si_addr = (void *)current->thread.faddr;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 5d19ed07e99d..0ae4a731cc12 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -699,11 +699,12 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
asmlinkage void do_ov(struct pt_regs *regs)
{
enum ctx_state prev_state;
- siginfo_t info = {
- .si_signo = SIGFPE,
- .si_code = FPE_INTOVF,
- .si_addr = (void __user *)regs->cp0_epc,
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGFPE;
+ info.si_code = FPE_INTOVF;
+ info.si_addr = (void __user *)regs->cp0_epc;

prev_state = exception_enter();
die_if_kernel("Integer overflow", regs);
@@ -721,7 +722,11 @@ asmlinkage void do_ov(struct pt_regs *regs)
void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
struct task_struct *tsk)
{
- struct siginfo si = { .si_addr = fault_addr, .si_signo = SIGFPE };
+ struct siginfo si;
+
+ clear_siginfo(&si);
+ si.si_addr = fault_addr;
+ si.si_signo = SIGFPE;

if (fcr31 & FPU_CSR_INV_X)
si.si_code = FPE_FLTINV;
@@ -739,9 +744,10 @@ void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,

int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
{
- struct siginfo si = { 0 };
+ struct siginfo si;
struct vm_area_struct *vma;

+ clear_siginfo(&si);
switch (sig) {
case 0:
return 0;
@@ -890,9 +896,10 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code,
const char *str)
{
- siginfo_t info = { 0 };
+ siginfo_t info;
char b[40];

+ clear_siginfo(&info);
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
if (kgdb_ll_trap(DIE_TRAP, str, regs, code, current->thread.trap_nr,
SIGTRAP) == NOTIFY_STOP)
@@ -1499,9 +1506,13 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
*/
asmlinkage void do_watch(struct pt_regs *regs)
{
- siginfo_t info = { .si_signo = SIGTRAP, .si_code = TRAP_HWBKPT };
+ siginfo_t info;
enum ctx_state prev_state;

+ clear_siginfo(&info);
+ info.si_signo = SIGTRAP;
+ info.si_code = TRAP_HWBKPT;
+
prev_state = exception_enter();
/*
* Clear WP (bit 22) bit of cause register so we don't loop
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index de3eae813e52..479d8033a801 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -163,11 +163,13 @@ static tilepro_bundle_bits rewrite_load_store_unaligned(
* actual bad address in an SPR, which it doesn't.
*/
if (align_ctl == 0) {
- siginfo_t info = {
- .si_signo = SIGBUS,
- .si_code = BUS_ADRALN,
- .si_addr = addr
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGBUS;
+ info.si_code = BUS_ADRALN;
+ info.si_addr = addr;
+
trace_unhandled_signal("unaligned trap", regs,
(unsigned long)addr, SIGBUS);
force_sig_info(info.si_signo, &info, current);
@@ -210,11 +212,13 @@ static tilepro_bundle_bits rewrite_load_store_unaligned(
}

if (err) {
- siginfo_t info = {
- .si_signo = SIGBUS,
- .si_code = BUS_ADRALN,
- .si_addr = addr
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGBUS;
+ info.si_code = BUS_ADRALN;
+ info.si_addr = addr;
+
trace_unhandled_signal("bad address for unaligned fixup", regs,
(unsigned long)addr, SIGBUS);
force_sig_info(info.si_signo, &info, current);
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 9b08c6055f15..83a7186198d7 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -256,12 +256,14 @@ static int do_bpt(struct pt_regs *regs)
void __kprobes do_trap(struct pt_regs *regs, int fault_num,
unsigned long reason)
{
- siginfo_t info = { 0 };
+ siginfo_t info;
int signo, code;
unsigned long address = 0;
tile_bundle_bits instr;
int is_kernel = !user_mode(regs);

+ clear_siginfo(&info);
+
/* Handle breakpoints, etc. */
if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
return;
diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c
index 8149c38f67b6..77a0b6b6a2a1 100644
--- a/arch/tile/kernel/unaligned.c
+++ b/arch/tile/kernel/unaligned.c
@@ -980,11 +980,13 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle,
}

if ((align_ctl == 0) || unexpected) {
- siginfo_t info = {
- .si_signo = SIGBUS,
- .si_code = BUS_ADRALN,
- .si_addr = (unsigned char __user *)0
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGBUS;
+ info.si_code = BUS_ADRALN;
+ info.si_addr = (unsigned char __user *)0;
+
if (unaligned_printk)
pr_info("Unalign bundle: unexp @%llx, %llx\n",
(unsigned long long)regs->pc,
@@ -1396,11 +1398,12 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle,
&frag, sizeof(frag));
if (status) {
/* Fail to copy JIT into user land. send SIGSEGV. */
- siginfo_t info = {
- .si_signo = SIGSEGV,
- .si_code = SEGV_MAPERR,
- .si_addr = (void __user *)&jit_code_area[idx]
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGSEGV;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = (void __user *)&jit_code_area[idx];

pr_warn("Unalign fixup: pid=%d %s jit_code_area=%llx\n",
current->pid, current->comm,
@@ -1511,11 +1514,12 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
* If so, we will trigger SIGBUS.
*/
if ((regs->sp & 0x7) || (regs->ex1) || (align_ctl < 0)) {
- siginfo_t info = {
- .si_signo = SIGBUS,
- .si_code = BUS_ADRALN,
- .si_addr = (unsigned char __user *)0
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGBUS;
+ info.si_code = BUS_ADRALN;
+ info.si_addr = (unsigned char __user *)0;

if (unaligned_printk)
pr_info("Unalign fixup: %d %llx @%llx\n",
@@ -1535,11 +1539,13 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
pc = (tilegx_bundle_bits __user *)(regs->pc);
if (get_user(bundle, pc) != 0) {
/* Probably never be here since pc is valid user address.*/
- siginfo_t info = {
- .si_signo = SIGSEGV,
- .si_code = SEGV_MAPERR,
- .si_addr = (void __user *)pc
- };
+ siginfo_t info;
+
+ clear_siginfo(&info);
+ info.si_signo = SIGSEGV;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = (void __user *)pc;
+
pr_err("Couldn't read instruction at %p trying to step\n", pc);
trace_unhandled_signal("segfault in unalign fixup", regs,
(unsigned long)info.si_addr, SIGSEGV);
diff --git a/kernel/signal.c b/kernel/signal.c
index 4976f05aa09b..f14492ff976f 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3163,8 +3163,9 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)

static int do_tkill(pid_t tgid, pid_t pid, int sig)
{
- struct siginfo info = {};
+ struct siginfo info;

+ clear_siginfo(&info);
info.si_signo = sig;
info.si_errno = 0;
info.si_code = SI_TKILL;
--
2.14.1


2018-01-23 21:12:12

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 04/10] signal: Replace memset(info,...) with clear_siginfo for clarity

The function clear_siginfo is just a nice wrapper around memset so
this results in no functional change. This change makes mistakes
a little more difficult and it makes it clearer what is going on.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/um/kernel/trap.c | 2 +-
drivers/usb/core/devio.c | 4 ++--
kernel/seccomp.c | 2 +-
kernel/time/posix-timers.c | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 428644175956..b2b02df9896e 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -306,7 +306,7 @@ void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)

arch_examine_signal(sig, regs);

- memset(&clean_si, 0, sizeof(clean_si));
+ clear_siginfo(&clean_si);
clean_si.si_signo = si->si_signo;
clean_si.si_errno = si->si_errno;
clean_si.si_code = si->si_code;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index a3fad4ec9870..3f9bd3e4c373 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -595,7 +595,7 @@ static void async_completed(struct urb *urb)
as->status = urb->status;
signr = as->signr;
if (signr) {
- memset(&sinfo, 0, sizeof(sinfo));
+ clear_siginfo(&sinfo);
sinfo.si_signo = as->signr;
sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO;
@@ -2613,7 +2613,7 @@ static void usbdev_remove(struct usb_device *udev)
wake_up_all(&ps->wait);
list_del_init(&ps->list);
if (ps->discsignr) {
- memset(&sinfo, 0, sizeof(sinfo));
+ clear_siginfo(&sinfo);
sinfo.si_signo = ps->discsignr;
sinfo.si_errno = EPIPE;
sinfo.si_code = SI_ASYNCIO;
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 5f0dfb2abb8d..3153c9ea51bf 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -515,7 +515,7 @@ void put_seccomp_filter(struct task_struct *tsk)

static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
{
- memset(info, 0, sizeof(*info));
+ clear_siginfo(info);
info->si_signo = SIGSYS;
info->si_code = SYS_SECCOMP;
info->si_call_addr = (void __user *)KSTK_EIP(current);
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index ec999f32c840..75043046914e 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -462,7 +462,7 @@ static struct k_itimer * alloc_posix_timer(void)
kmem_cache_free(posix_timers_cache, tmr);
return NULL;
}
- memset(&tmr->sigq->info, 0, sizeof(siginfo_t));
+ clear_siginfo(&tmr->sigq->info);
return tmr;
}

--
2.14.1


2018-01-23 21:12:46

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 02/10] signal/arm64: Better isolate the COMPAT_TASK portion of ptrace_hbptriggered

Instead of jumpping while !is_compat_task placee all of the code
inside of an if (is_compat_task) block. This allows the int i
variable to be properly limited to the compat block no matter how the
rest of ptrace_hbptriggered changes.

In a following change a non-variable declaration will preceed
was made independent to ensure the code is easy to review.

Signed-off-by: "Eric W. Biederman" <[email protected]>
---
arch/arm64/kernel/ptrace.c | 27 ++++++++++++---------------
1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 7c44658b316d..0a1cf830e4b3 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -188,26 +188,23 @@ static void ptrace_hbptriggered(struct perf_event *bp,
};

#ifdef CONFIG_COMPAT
- int i;
-
- if (!is_compat_task())
- goto send_sig;
+ if (is_compat_task()) {
+ int i;

- for (i = 0; i < ARM_MAX_BRP; ++i) {
- if (current->thread.debug.hbp_break[i] == bp) {
- info.si_errno = (i << 1) + 1;
- break;
+ for (i = 0; i < ARM_MAX_BRP; ++i) {
+ if (current->thread.debug.hbp_break[i] == bp) {
+ info.si_errno = (i << 1) + 1;
+ break;
+ }
}
- }

- for (i = 0; i < ARM_MAX_WRP; ++i) {
- if (current->thread.debug.hbp_watch[i] == bp) {
- info.si_errno = -((i << 1) + 1);
- break;
+ for (i = 0; i < ARM_MAX_WRP; ++i) {
+ if (current->thread.debug.hbp_watch[i] == bp) {
+ info.si_errno = -((i << 1) + 1);
+ break;
+ }
}
}
-
-send_sig:
#endif
force_sig_info(SIGTRAP, &info, current);
}
--
2.14.1


2018-01-24 19:27:24

by Ram Pai

[permalink] [raw]
Subject: Re: [PATCH 06/10] signal: Helpers for faults with specialized siginfo layouts

On Tue, Jan 23, 2018 at 03:07:15PM -0600, Eric W. Biederman wrote:
> The helpers added are:
> send_sig_mceerr
> force_sig_mceerr
> force_sig_bnderr
> force_sig_pkuerr
>
> Filling out siginfo properly can ge tricky. Especially for these
> specialized cases where the temptation is to share code with other
> cases which use a different subset of siginfo fields. Unfortunately
> that code sharing frequently results in bugs with the wrong siginfo
> fields filled in, and makes it harder to verify that the siginfo
> structure was properly initialized.
>
> Provide these helpers instead that get all of the details right, and
> guarantee that siginfo is properly initialized.
>
> send_sig_mceerr and force_sig_mceer are a little special as two si
> codes BUS_MCEERR_AO and BUS_MCEER_AR both use the same extended
> signinfo layout.

nice. i can make use of these helpers in the memory-key implementation.

One small nit-pick below though...

>
> Signed-off-by: "Eric W. Biederman" <[email protected]>
> ---
> include/linux/sched/signal.h | 6 +++++
> kernel/signal.c | 61 ++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 67 insertions(+)
>
> diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h

...snip..

> +
> +#ifdef SEGV_PKUERR

Should this really be under SEGV_PKUERR ? that macro is defined
unconditionally anyway.

> +int force_sig_pkuerr(void __user *addr, u32 pkey)
> +{
> + struct siginfo info;
> +
> + clear_siginfo(&info);
> + info.si_signo = SIGSEGV;
> + info.si_errno = 0;
> + info.si_code = SEGV_PKUERR;
> + info.si_addr = addr;
> + info.si_pkey = pkey;
> + return force_sig_info(info.si_signo, &info, current);
> +}
> +#endif


2018-01-24 20:56:51

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 06/10] signal: Helpers for faults with specialized siginfo layouts

Ram Pai <[email protected]> writes:

> On Tue, Jan 23, 2018 at 03:07:15PM -0600, Eric W. Biederman wrote:
>> The helpers added are:
>> send_sig_mceerr
>> force_sig_mceerr
>> force_sig_bnderr
>> force_sig_pkuerr
>>
>> Filling out siginfo properly can ge tricky. Especially for these
>> specialized cases where the temptation is to share code with other
>> cases which use a different subset of siginfo fields. Unfortunately
>> that code sharing frequently results in bugs with the wrong siginfo
>> fields filled in, and makes it harder to verify that the siginfo
>> structure was properly initialized.
>>
>> Provide these helpers instead that get all of the details right, and
>> guarantee that siginfo is properly initialized.
>>
>> send_sig_mceerr and force_sig_mceer are a little special as two si
>> codes BUS_MCEERR_AO and BUS_MCEER_AR both use the same extended
>> signinfo layout.
>
> nice. i can make use of these helpers in the memory-key implementation.
>
> One small nit-pick below though...
>
>>
>> Signed-off-by: "Eric W. Biederman" <[email protected]>
>> ---
>> include/linux/sched/signal.h | 6 +++++
>> kernel/signal.c | 61 ++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 67 insertions(+)
>>
>> diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
>
> ...snip..
>
>> +
>> +#ifdef SEGV_PKUERR
>
> Should this really be under SEGV_PKUERR ? that macro is defined
> unconditionally anyway.

Unless you are running my unified siginfo.h (from an earlier patchset
which I build upon). It turns out that ia64 has a conflict for that
number. So ia64 really can't use the define and this infrastructure.

We might decide to sort that out and always have SEGV_PKUERR always
defined. Sadly for the moment the #ifdef is necessary.

>> +int force_sig_pkuerr(void __user *addr, u32 pkey)
>> +{
>> + struct siginfo info;
>> +
>> + clear_siginfo(&info);
>> + info.si_signo = SIGSEGV;
>> + info.si_errno = 0;
>> + info.si_code = SEGV_PKUERR;
>> + info.si_addr = addr;
>> + info.si_pkey = pkey;
>> + return force_sig_info(info.si_signo, &info, current);
>> +}
>> +#endif

Eric

2018-01-24 21:31:46

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 07/11] signal/arm64: Document conflicts with SI_USER and SIGFPE, SIGTRAP, SIGBUS

Russell King - ARM Linux <[email protected]> writes:

> On Wed, Jan 17, 2018 at 10:45:10AM -0600, Eric W. Biederman wrote:
>> Russell King - ARM Linux <[email protected]> writes:
>> >From your description there still seems to be an association with an
>> instruction so I don't know if I would really call the signal
>> asynchronous. It sounds like the exception is delayed and not
>> asynchronous.
>
> Traps can only be passed from ARM coprocessors by a coprocessor refusing
> to execute an instruction. That's what happens in this case - the VFP
> gets offered an instruction to execute. It accepts it, and the CPU
> continues, leaving the VFP to execute its instruction independently. If
> this instruction generates an error, then nothing happens at this point.
>
> That error remains pending until the CPU offers the coprocessor the next
> VFP instruction, which it refuses. That causes an undefined instruction
> exception, and we trap into the kernel VFP code which reads the VFP
> status and works out what needs to be done.
>
> What this means is that if you execute a VFP instruction, wait 10 minutes
> and then execute another VFP instruction, if the first VFP instruction
> raised an exception, you'll get to hear about it 10 minutes later.
>
> You can use whatever weasel words you want to describe that situation,
> my choice is "asynchronous", your choice is "delayed". However, it is
> clearly not "synchronous", and arguing that we should report something
> synchronously that is not reported to _us_ synchronously (where
> synchronous means "at the same time") is IMHO daft.
>
> So, let's take an example:
>
> installs SIGFPE handler
> ..fp instructions.. one of which raises an exception
> returns to main loop
> main loop blocks all signals while it sets stuff up
> calls ppoll()
>
> In the synchronous SIGFPE delivery case, the SIGFPE handler will be
> called when the exception is generated in the FP code, and delivered
> at that time. The fact that the main loop blocks all signals happens
> later, so the users handler gets called as one expects.
>
> In the VFP case, however, the FP instructions towards the end may not
> end up causing the exception to be signalled until sometime later,
> and as I've already explained, that may be the result of a C library
> function accessing the VFP registers. This could well end up trying
> to deliver the SIGFPE while signals are blocked, and we get
> drastically different behaviour if force_sig_info() is used.
>
> In the VFP case, if force_sig_info() is used, the program gets killed
> at this point. In the non-VFP case, the program's signal handler was
> called.
>
> Using send_sig_info() results in the already delayed or asynchronous
> signal being held off until ppoll() drops the blocking, at which point
> the signal is delivered, the program handles it in its handler, and
> the program continues to run.
>
> So
> 1. non-VFP case, program doesn't get killed but gets the opportunity
> to handle the signal.
> 2. VFP case with send_sig_info, program doesn't get killed but gets
> the opportunity to handle the signal.
> 3. VFP case with force_sig_info, the program gets killed and dumps
> core.
>
> Which one of these results in a big change of behaviour in your
> opinion?

I want to apologize for the disagreement. In part of my due diligence
for cleaning up the signal handling I am introducing some helpers for
generating siginfo. I decided to ask which kind of helpers should I
introduce.

Very basic generic helpers that just wrap the current functionality
today. Or some slightly smarter helpers that solve some other problems
as well. After consideration I am shelving the smarter helpers for now,
as the need to introduce the helpers universally is strong, so that I
can guarantee struct siginfo is always fully initialized before being
passed to userspace.

Given the choice between force_sig_info and send_sig_info I agree that
send_sig_info is the right choice for signals that can be ignored.

The problem I was focusing on is the problem where force_sig_info and
send_sig_info can be tricked into causing the instruction pointer to
point to the wrong instruction (even when the signal is not blocked),
due to the delivery of another signal.

So I was wondering if in practice we could introduce a singal delivery
function that would operation synchronously and would solve the
instruction pointer problem.

It looks to me like this location on arm where we are using
send_sig_info is a clear candidate for such a function as long as it has
a mode where you can say deliverly the signal like send_sig_info if the
signal is blocked.

Still like I said such a smarter helper is not the priority and I don't
intend any semantic changes when I introduce helpers into the signal
deliver path. Just fewer places initializing struct siginfo.

Eric

2018-02-23 00:17:24

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE

Helge Deller <[email protected]> writes:

> * Eric W. Biederman <[email protected]>:
>> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>> This is the same si_code as SI_USER. Posix and common sense requires
>> that SI_USER not be a signal specific si_code. As such this use of 0
>> for the si_code is a pretty horribly broken ABI.
>>
>> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>> value of __SI_KILL and now sees a value of SIL_KILL with the result
>> that uid and pid fields are copied and which might copying the si_addr
>> field by accident but certainly not by design. Making this a very
>> flakey implementation.
>>
>> Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
>> appropriate fields will reliably be copied.
>>
>> This bug is 13 years old and parsic machines are no longer being built
>> so I don't know if it possible or worth fixing it. But it is at least
>> worth documenting this so other architectures don't make the same
>> mistake.
>
>
> I think we should fix it, even if we now break the ABI.
>
> It's about a "conditional trap" which needs to be handled by userspace.
> I doubt there is any Linux code out which is utilizing this
> parisc-specific trap.
>
> I'd suggest to add a new FPE trap si_code (e.g. FPE_CONDTRAP).
> While at it, maybe we should include the already existing FPE_MDAOVF
> from the frv architecture, so that arch/frv/include/uapi/asm/siginfo.h
> can go completely.
>
> Suggested patch is below.
>
> I'm willing to test the patch below on the parisc architecture for a few
> weeks. And it will break arch/x86/kernel/signal_compat.c which needs
> looking at then too.

Have you managed to test this change?

I am sitting looking at another new FPE si_code and if this has been tested
I figure FPE_CONDTRAP should get the next available FPE si_code and the
other change should get the one that follows.

Eric

2018-02-25 19:52:08

by Helge Deller

[permalink] [raw]
Subject: Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE

On 23.02.2018 01:15, Eric W. Biederman wrote:
> Helge Deller <[email protected]> writes:
>
>> * Eric W. Biederman <[email protected]>:
>>> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>>> This is the same si_code as SI_USER. Posix and common sense requires
>>> that SI_USER not be a signal specific si_code. As such this use of 0
>>> for the si_code is a pretty horribly broken ABI.
>>>
>>> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>>> value of __SI_KILL and now sees a value of SIL_KILL with the result
>>> that uid and pid fields are copied and which might copying the si_addr
>>> field by accident but certainly not by design. Making this a very
>>> flakey implementation.
>>>
>>> Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
>>> appropriate fields will reliably be copied.
>>>
>>> This bug is 13 years old and parsic machines are no longer being built
>>> so I don't know if it possible or worth fixing it. But it is at least
>>> worth documenting this so other architectures don't make the same
>>> mistake.
>>
>>
>> I think we should fix it, even if we now break the ABI.
>>
>> It's about a "conditional trap" which needs to be handled by userspace.
>> I doubt there is any Linux code out which is utilizing this
>> parisc-specific trap.
>>
>> I'd suggest to add a new FPE trap si_code (e.g. FPE_CONDTRAP).
>> While at it, maybe we should include the already existing FPE_MDAOVF
>> from the frv architecture, so that arch/frv/include/uapi/asm/siginfo.h
>> can go completely.
>>
>> Suggested patch is below.
>>
>> I'm willing to test the patch below on the parisc architecture for a few
>> weeks. And it will break arch/x86/kernel/signal_compat.c which needs
>> looking at then too.
>
> Have you managed to test this change?

Sadly I haven't done any further testing yet.

> I am sitting looking at another new FPE si_code and if this has been tested
> I figure FPE_CONDTRAP should get the next available FPE si_code and the
> other change should get the one that follows.

I'm fine either way. Do you have a git tree I can pull which includes
all your patches? I can then start testing.

Helge

2018-02-27 02:21:56

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 04/11] signal/parisc: Document a conflict with SI_USER with SIGFPE

Helge Deller <[email protected]> writes:

> On 23.02.2018 01:15, Eric W. Biederman wrote:
>> Helge Deller <[email protected]> writes:
>>
>>> * Eric W. Biederman <[email protected]>:
>>>> Setting si_code to 0 results in a userspace seeing an si_code of 0.
>>>> This is the same si_code as SI_USER. Posix and common sense requires
>>>> that SI_USER not be a signal specific si_code. As such this use of 0
>>>> for the si_code is a pretty horribly broken ABI.
>>>>
>>>> Further use of si_code == 0 guaranteed that copy_siginfo_to_user saw a
>>>> value of __SI_KILL and now sees a value of SIL_KILL with the result
>>>> that uid and pid fields are copied and which might copying the si_addr
>>>> field by accident but certainly not by design. Making this a very
>>>> flakey implementation.
>>>>
>>>> Utilizing FPE_FIXME siginfo_layout will now return SIL_FAULT and the
>>>> appropriate fields will reliably be copied.
>>>>
>>>> This bug is 13 years old and parsic machines are no longer being built
>>>> so I don't know if it possible or worth fixing it. But it is at least
>>>> worth documenting this so other architectures don't make the same
>>>> mistake.
>>>
>>>
>>> I think we should fix it, even if we now break the ABI.
>>>
>>> It's about a "conditional trap" which needs to be handled by userspace.
>>> I doubt there is any Linux code out which is utilizing this
>>> parisc-specific trap.
>>>
>>> I'd suggest to add a new FPE trap si_code (e.g. FPE_CONDTRAP).
>>> While at it, maybe we should include the already existing FPE_MDAOVF
>>> from the frv architecture, so that arch/frv/include/uapi/asm/siginfo.h
>>> can go completely.
>>>
>>> Suggested patch is below.
>>>
>>> I'm willing to test the patch below on the parisc architecture for a few
>>> weeks. And it will break arch/x86/kernel/signal_compat.c which needs
>>> looking at then too.
>>
>> Have you managed to test this change?
>
> Sadly I haven't done any further testing yet.

So at this point for purposed of testing I don't think it matters which
number FPE_CONDTRAP gets as long as it is non-zero.
>
>> I am sitting looking at another new FPE si_code and if this has been tested
>> I figure FPE_CONDTRAP should get the next available FPE si_code and the
>> other change should get the one that follows.
>
> I'm fine either way. Do you have a git tree I can pull which includes
> all your patches? I can then start testing.

Everything finalized is in Linus's tree. There is a patch pending
review on linux-arch that defines FPE_FLTUNK that looks to be useful
on several architectures.

I had probably misread our earlier exchange. I had hoped you had tested
that FPE_CONDTRAP did not cause problems.

If that level of testing was complete I would have given FPE_CONDTRAP
the next FPE number and FPE_FLTUNK the one after.

As it sounds like FPE_CONDTRAP hasn't been tested enough to know if it
causes problems I will encourage the patches to be merged in the other
order.

Eric


2018-03-16 19:02:32

by Dave Hansen

[permalink] [raw]
Subject: Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity

On 01/15/2018 04:40 PM, Eric W. Biederman wrote:
> The addr_lsb fields is only valid and available when the
> signal is SIGBUS and the si_code is BUS_MCEERR_AR or BUS_MCEERR_AO.
> Document this with a comment and place the field in the _sigfault union
> to make this clear.
>
> All of the fields stay in the same physical location so both the old
> and new definitions of struct siginfo will continue to work.

This breaks the ABI and breaks protection keys. The physical locations
*DO* change.

Before this patch:

#define si_pkey _sifields._sigfault._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._pkey
$1 = (__u32 *) 0x20 <irq_stack_union+32>

and after:

+#define si_pkey _sifields._sigfault._addr_pkey._pkey
(gdb) print &((siginfo_t *)0)->_sifields._sigfault._addr_pkey._pkey
$1 = (__u32 *) 0x1c

Can we revert this, please?

2018-03-16 19:26:19

by Dave Hansen

[permalink] [raw]
Subject: Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity

On 03/16/2018 12:00 PM, Dave Hansen wrote:
> On 01/15/2018 04:40 PM, Eric W. Biederman wrote:
>> The addr_lsb fields is only valid and available when the
>> signal is SIGBUS and the si_code is BUS_MCEERR_AR or BUS_MCEERR_AO.
>> Document this with a comment and place the field in the _sigfault union
>> to make this clear.
>>
>> All of the fields stay in the same physical location so both the old
>> and new definitions of struct siginfo will continue to work.
>
> This breaks the ABI and breaks protection keys. The physical locations
> *DO* change.
>
> Before this patch:
>
> #define si_pkey _sifields._sigfault._pkey
> (gdb) print &((siginfo_t *)0)->_sifields._sigfault._pkey
> $1 = (__u32 *) 0x20 <irq_stack_union+32>
>
> and after:
>
> +#define si_pkey _sifields._sigfault._addr_pkey._pkey
> (gdb) print &((siginfo_t *)0)->_sifields._sigfault._addr_pkey._pkey
> $1 = (__u32 *) 0x1c
>
> Can we revert this, please?

It does not revert cleanly so I reverted it manually. Patch doing that
is attached. Should we do this, or is there a better option?


Attachments:
revert-b68a68d3dcc15ebbf23cbe91af1abf57591bd96b.patch (2.66 kB)

2018-03-16 20:10:20

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity

Dave Hansen <[email protected]> writes:

> On 03/16/2018 12:00 PM, Dave Hansen wrote:
>> On 01/15/2018 04:40 PM, Eric W. Biederman wrote:
>>> The addr_lsb fields is only valid and available when the
>>> signal is SIGBUS and the si_code is BUS_MCEERR_AR or BUS_MCEERR_AO.
>>> Document this with a comment and place the field in the _sigfault union
>>> to make this clear.
>>>
>>> All of the fields stay in the same physical location so both the old
>>> and new definitions of struct siginfo will continue to work.
>>
>> This breaks the ABI and breaks protection keys. The physical locations
>> *DO* change.
>>
>> Before this patch:
>>
>> #define si_pkey _sifields._sigfault._pkey
>> (gdb) print &((siginfo_t *)0)->_sifields._sigfault._pkey
>> $1 = (__u32 *) 0x20 <irq_stack_union+32>
>>
>> and after:
>>
>> +#define si_pkey _sifields._sigfault._addr_pkey._pkey
>> (gdb) print &((siginfo_t *)0)->_sifields._sigfault._addr_pkey._pkey
>> $1 = (__u32 *) 0x1c
>>
>> Can we revert this, please?
>
> It does not revert cleanly so I reverted it manually. Patch doing that
> is attached. Should we do this, or is there a better option?

Please see:
859d880cf544 ("signal: Correct the offset of si_pkey in struct siginfo")

Eric

2018-03-16 20:34:48

by Dave Hansen

[permalink] [raw]
Subject: Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity

On 03/16/2018 01:06 PM, Eric W. Biederman wrote:
>> It does not revert cleanly so I reverted it manually. Patch doing that
>> is attached. Should we do this, or is there a better option?
> Please see:
> 859d880cf544 ("signal: Correct the offset of si_pkey in struct siginfo")

It would be really nice to actually cc the folks that wrote and maintain
the code when you both break their stuff and fix it. I don't see myself
or the x86 maintainers cc'd on any of this: the patch that caused the
breakage *or* the fix.

2018-03-16 21:11:29

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 13/22] signal: Move addr_lsb into the _sigfault union for clarity

Dave Hansen <[email protected]> writes:

> On 03/16/2018 01:06 PM, Eric W. Biederman wrote:
>>> It does not revert cleanly so I reverted it manually. Patch doing that
>>> is attached. Should we do this, or is there a better option?
>> Please see:
>> 859d880cf544 ("signal: Correct the offset of si_pkey in struct siginfo")
>
> It would be really nice to actually cc the folks that wrote and maintain
> the code when you both break their stuff and fix it. I don't see myself
> or the x86 maintainers cc'd on any of this: the patch that caused the
> breakage *or* the fix.

What I touched was in no way x86 or pkey specific code. The email alias
for all of the arch maintainers in the kernel is called linux-arch. It
is hard to find who cares bits of essentially unmaintained code in the
kernel.

The fix was merged via the usual process and is available to everyone,
and is not hard to find. It was labeled with an appropriate fixes tag.

I was also very careful to ensure that I fixed the regression I
accidentally introduced and did not introduce another ABI regression
with any other field:
f6a015498dca ("signal/x86: Include the field offsets in the build time checks")

Eric