Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 191273
b: refs/heads/master
c: b2812d0
h: refs/heads/master
i:
  191271: 955e80a
v: v3
  • Loading branch information
Frederic Weisbecker committed May 1, 2010
1 parent e93c4b5 commit b4e0cfd
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 71 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 87e9b2024659c614a876ce359a57e98a47b5ef37
refs/heads/master: b2812d031dea86926e9c10f7714af33ac2f6b43d
5 changes: 2 additions & 3 deletions trunk/arch/sh/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ struct pmu;
#define HBP_NUM 2

/* arch/sh/kernel/hw_breakpoint.c */
extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk);
extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);

Expand Down
34 changes: 7 additions & 27 deletions trunk/arch/sh/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,26 +119,17 @@ static int get_hbp_len(u16 hbp_len)
return len_in_bytes;
}

/*
* Check for virtual address in user space.
*/
int arch_check_va_in_userspace(unsigned long va, u16 hbp_len)
{
unsigned int len;

len = get_hbp_len(hbp_len);

return (va <= TASK_SIZE - len);
}

/*
* Check for virtual address in kernel space.
*/
static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len)
int arch_check_bp_in_kernelspace(struct perf_event *bp)
{
unsigned int len;
unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);

len = get_hbp_len(hbp_len);
va = info->address;
len = get_hbp_len(info->len);

return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
}
Expand Down Expand Up @@ -226,8 +217,7 @@ static int arch_build_bp_info(struct perf_event *bp)
/*
* Validate the arch-specific HW Breakpoint register settings
*/
int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk)
int arch_validate_hwbkpt_settings(struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
unsigned int align;
Expand Down Expand Up @@ -270,15 +260,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp,
if (info->address & align)
return -EINVAL;

/* Check that the virtual address is in the proper range */
if (tsk) {
if (!arch_check_va_in_userspace(info->address, info->len))
return -EFAULT;
} else {
if (!arch_check_va_in_kernelspace(info->address, info->len))
return -EFAULT;
}

return 0;
}

Expand Down Expand Up @@ -363,8 +344,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
perf_bp_event(bp, args->regs);

/* Deliver the signal to userspace */
if (arch_check_va_in_userspace(bp->attr.bp_addr,
bp->attr.bp_len)) {
if (!arch_check_bp_in_kernelspace(bp)) {
siginfo_t info;

info.si_signo = args->signr;
Expand Down
5 changes: 2 additions & 3 deletions trunk/arch/x86/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ struct arch_hw_breakpoint {
struct perf_event;
struct pmu;

extern int arch_check_va_in_userspace(unsigned long va, u8 hbp_len);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk);
extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);

Expand Down
41 changes: 6 additions & 35 deletions trunk/arch/x86/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,26 +188,17 @@ static int get_hbp_len(u8 hbp_len)
return len_in_bytes;
}

/*
* Check for virtual address in user space.
*/
int arch_check_va_in_userspace(unsigned long va, u8 hbp_len)
{
unsigned int len;

len = get_hbp_len(hbp_len);

return (va <= TASK_SIZE - len);
}

/*
* Check for virtual address in kernel space.
*/
static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len)
int arch_check_bp_in_kernelspace(struct perf_event *bp)
{
unsigned int len;
unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);

len = get_hbp_len(hbp_len);
va = info->address;
len = get_hbp_len(info->len);

return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
}
Expand Down Expand Up @@ -300,8 +291,7 @@ static int arch_build_bp_info(struct perf_event *bp)
/*
* Validate the arch-specific HW Breakpoint register settings
*/
int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk)
int arch_validate_hwbkpt_settings(struct perf_event *bp)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
unsigned int align;
Expand All @@ -314,16 +304,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp,

ret = -EINVAL;

if (info->type == X86_BREAKPOINT_EXECUTE)
/*
* Ptrace-refactoring code
* For now, we'll allow instruction breakpoint only for user-space
* addresses
*/
if ((!arch_check_va_in_userspace(info->address, info->len)) &&
info->len != X86_BREAKPOINT_EXECUTE)
return ret;

switch (info->len) {
case X86_BREAKPOINT_LEN_1:
align = 0;
Expand All @@ -350,15 +330,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp,
if (info->address & align)
return -EINVAL;

/* Check that the virtual address is in the proper range */
if (tsk) {
if (!arch_check_va_in_userspace(info->address, info->len))
return -EFAULT;
} else {
if (!arch_check_va_in_kernelspace(info->address, info->len))
return -EFAULT;
}

return 0;
}

Expand Down
26 changes: 24 additions & 2 deletions trunk/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,28 @@ int dbg_release_bp_slot(struct perf_event *bp)
return 0;
}

static int validate_hw_breakpoint(struct perf_event *bp)
{
int ret;

ret = arch_validate_hwbkpt_settings(bp);
if (ret)
return ret;

if (arch_check_bp_in_kernelspace(bp)) {
if (bp->attr.exclude_kernel)
return -EINVAL;
/*
* Don't let unprivileged users set a breakpoint in the trap
* path to avoid trap recursion attacks.
*/
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
}

return 0;
}

int register_perf_hw_breakpoint(struct perf_event *bp)
{
int ret;
Expand All @@ -316,7 +338,7 @@ int register_perf_hw_breakpoint(struct perf_event *bp)
if (ret)
return ret;

ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
ret = validate_hw_breakpoint(bp);

/* if arch_validate_hwbkpt_settings() fails then release bp slot */
if (ret)
Expand Down Expand Up @@ -363,7 +385,7 @@ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *att
if (attr->disabled)
goto end;

err = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
err = validate_hw_breakpoint(bp);
if (!err)
perf_event_enable(bp);

Expand Down

0 comments on commit b4e0cfd

Please sign in to comment.