diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2018-01-22 15:37:25 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2018-01-22 20:07:11 -0500 |
commit | f71dd7dc2dc989dc712b246a74d243e4b2c5f8a7 (patch) | |
tree | c126cf571c0a25c540210fa7bfe8f03b19d0c2a4 | |
parent | 47355040d2760566901057287b35d5f10e217e12 (diff) |
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" <ebiederm@xmission.com>
-rw-r--r-- | arch/arm/kernel/ptrace.c | 8 | ||||
-rw-r--r-- | arch/arm64/kernel/ptrace.c | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 9 | ||||
-rw-r--r-- | arch/xtensa/kernel/ptrace.c | 8 | ||||
-rw-r--r-- | include/linux/sched/signal.h | 2 | ||||
-rw-r--r-- | 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, | |||
390 | struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); | 390 | struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); |
391 | long num; | 391 | long num; |
392 | int i; | 392 | int i; |
393 | siginfo_t info; | ||
394 | 393 | ||
395 | for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i) | 394 | for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i) |
396 | if (current->thread.debug.hbp[i] == bp) | 395 | if (current->thread.debug.hbp[i] == bp) |
@@ -398,12 +397,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, | |||
398 | 397 | ||
399 | num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i); | 398 | num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i); |
400 | 399 | ||
401 | info.si_signo = SIGTRAP; | 400 | force_sig_ptrace_errno_trap((int)num, (void __user *)(bkpt->trigger)); |
402 | info.si_errno = (int)num; | ||
403 | info.si_code = TRAP_HWBKPT; | ||
404 | info.si_addr = (void __user *)(bkpt->trigger); | ||
405 | |||
406 | force_sig_info(SIGTRAP, &info, current); | ||
407 | } | 401 | } |
408 | 402 | ||
409 | /* | 403 | /* |
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, | |||
190 | 190 | ||
191 | #ifdef CONFIG_COMPAT | 191 | #ifdef CONFIG_COMPAT |
192 | if (is_compat_task()) { | 192 | if (is_compat_task()) { |
193 | int si_errno = 0; | ||
193 | int i; | 194 | int i; |
194 | 195 | ||
195 | for (i = 0; i < ARM_MAX_BRP; ++i) { | 196 | for (i = 0; i < ARM_MAX_BRP; ++i) { |
196 | if (current->thread.debug.hbp_break[i] == bp) { | 197 | if (current->thread.debug.hbp_break[i] == bp) { |
197 | info.si_errno = (i << 1) + 1; | 198 | si_errno = (i << 1) + 1; |
198 | break; | 199 | break; |
199 | } | 200 | } |
200 | } | 201 | } |
201 | 202 | ||
202 | for (i = 0; i < ARM_MAX_WRP; ++i) { | 203 | for (i = 0; i < ARM_MAX_WRP; ++i) { |
203 | if (current->thread.debug.hbp_watch[i] == bp) { | 204 | if (current->thread.debug.hbp_watch[i] == bp) { |
204 | info.si_errno = -((i << 1) + 1); | 205 | si_errno = -((i << 1) + 1); |
205 | break; | 206 | break; |
206 | } | 207 | } |
207 | } | 208 | } |
209 | force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger); | ||
208 | } | 210 | } |
209 | #endif | 211 | #endif |
210 | force_sig_info(SIGTRAP, &info, current); | 212 | 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); | |||
603 | void do_send_trap(struct pt_regs *regs, unsigned long address, | 603 | void do_send_trap(struct pt_regs *regs, unsigned long address, |
604 | unsigned long error_code, int breakpt) | 604 | unsigned long error_code, int breakpt) |
605 | { | 605 | { |
606 | siginfo_t info; | ||
607 | |||
608 | current->thread.trap_nr = TRAP_HWBKPT; | 606 | current->thread.trap_nr = TRAP_HWBKPT; |
609 | if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, | 607 | if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, |
610 | 11, SIGSEGV) == NOTIFY_STOP) | 608 | 11, SIGSEGV) == NOTIFY_STOP) |
611 | return; | 609 | return; |
612 | 610 | ||
613 | /* Deliver the signal to userspace */ | 611 | /* Deliver the signal to userspace */ |
614 | info.si_signo = SIGTRAP; | 612 | force_sig_ptrace_errno_trap(breakpt, /* breakpoint or watchpoint id */ |
615 | info.si_errno = breakpt; /* breakpoint or watchpoint id */ | 613 | (void __user *)address); |
616 | info.si_code = TRAP_HWBKPT; | ||
617 | info.si_addr = (void __user *)address; | ||
618 | force_sig_info(SIGTRAP, &info, current); | ||
619 | } | 614 | } |
620 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ | 615 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ |
621 | void do_break (struct pt_regs *regs, unsigned long address, | 616 | 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, | |||
278 | struct pt_regs *regs) | 278 | struct pt_regs *regs) |
279 | { | 279 | { |
280 | int i; | 280 | int i; |
281 | siginfo_t info; | ||
282 | struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); | 281 | struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); |
283 | 282 | ||
284 | if (bp->attr.bp_type & HW_BREAKPOINT_X) { | 283 | if (bp->attr.bp_type & HW_BREAKPOINT_X) { |
@@ -293,12 +292,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, | |||
293 | i = (i << 1) | 1; | 292 | i = (i << 1) | 1; |
294 | } | 293 | } |
295 | 294 | ||
296 | info.si_signo = SIGTRAP; | 295 | force_sig_ptrace_errno_trap(i, (void __user *)bkpt->address); |
297 | info.si_errno = i; | ||
298 | info.si_code = TRAP_HWBKPT; | ||
299 | info.si_addr = (void __user *)bkpt->address; | ||
300 | |||
301 | force_sig_info(SIGTRAP, &info, current); | ||
302 | } | 296 | } |
303 | 297 | ||
304 | static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type) | 298 | 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 *); | |||
311 | int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper); | 311 | int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper); |
312 | int force_sig_pkuerr(void __user *addr, u32 pkey); | 312 | int force_sig_pkuerr(void __user *addr, u32 pkey); |
313 | 313 | ||
314 | int force_sig_ptrace_errno_trap(int errno, void __user *addr); | ||
315 | |||
314 | extern int send_sig_info(int, struct siginfo *, struct task_struct *); | 316 | extern int send_sig_info(int, struct siginfo *, struct task_struct *); |
315 | extern int force_sigsegv(int, struct task_struct *); | 317 | extern int force_sigsegv(int, struct task_struct *); |
316 | extern int force_sig_info(int, struct siginfo *, struct task_struct *); | 318 | 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) | |||
1599 | } | 1599 | } |
1600 | #endif | 1600 | #endif |
1601 | 1601 | ||
1602 | /* For the crazy architectures that include trap information in | ||
1603 | * the errno field, instead of an actual errno value. | ||
1604 | */ | ||
1605 | int force_sig_ptrace_errno_trap(int errno, void __user *addr) | ||
1606 | { | ||
1607 | struct siginfo info; | ||
1608 | |||
1609 | clear_siginfo(&info); | ||
1610 | info.si_signo = SIGTRAP; | ||
1611 | info.si_errno = errno; | ||
1612 | info.si_code = TRAP_HWBKPT; | ||
1613 | info.si_addr = addr; | ||
1614 | return force_sig_info(info.si_signo, &info, current); | ||
1615 | } | ||
1616 | |||
1602 | int kill_pgrp(struct pid *pid, int sig, int priv) | 1617 | int kill_pgrp(struct pid *pid, int sig, int priv) |
1603 | { | 1618 | { |
1604 | int ret; | 1619 | int ret; |