Skip to content

Commit

Permalink
signal/ptrace: Add force_sig_ptrace_errno_trap and use it where needed
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
ebiederm committed Jan 23, 2018
1 parent 4735504 commit f71dd7d
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 23 deletions.
8 changes: 1 addition & 7 deletions arch/arm/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,20 +390,14 @@ 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)
break;

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));
}

/*
Expand Down
6 changes: 4 additions & 2 deletions arch/arm64/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 2 additions & 7 deletions arch/powerpc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 1 addition & 7 deletions arch/xtensa/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions include/linux/sched/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
15 changes: 15 additions & 0 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit f71dd7d

Please sign in to comment.