Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 191279
b: refs/heads/master
c: 63e0c77
h: refs/heads/master
i:
  191277: e70e49a
  191275: 37b7ab2
  191271: 955e80a
  191263: 81def82
v: v3
  • Loading branch information
Tom Zanussi authored and Arnaldo Carvalho de Melo committed May 3, 2010
1 parent e3be830 commit 7c52e8e
Show file tree
Hide file tree
Showing 33 changed files with 284 additions and 259 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: 777d0411cd1e384115985dac5ccd42031e3eee2b
refs/heads/master: 63e0c7715aab6085faa487d498889f4361dc6542
11 changes: 0 additions & 11 deletions trunk/arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,6 @@ config HAVE_HW_BREAKPOINT
bool
depends on PERF_EVENTS

config HAVE_MIXED_BREAKPOINTS_REGS
bool
depends on HAVE_HW_BREAKPOINT
help
Depending on the arch implementation of hardware breakpoints,
some of them have separate registers for data and instruction
breakpoints addresses, others have mixed registers to store
them but define the access type in a control register.
Select this option if your arch implements breakpoints under the
latter fashion.

config HAVE_USER_RETURN_NOTIFIER
bool

Expand Down
1 change: 0 additions & 1 deletion trunk/arch/sh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ config SUPERH32
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_ARCH_KGDB
select HAVE_HW_BREAKPOINT
select HAVE_MIXED_BREAKPOINTS_REGS
select PERF_EVENTS if HAVE_HW_BREAKPOINT
select ARCH_HIBERNATION_POSSIBLE if MMU

Expand Down
10 changes: 3 additions & 7 deletions trunk/arch/sh/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,10 @@ struct pmu;
/* Maximum number of UBC channels */
#define HBP_NUM 2

static inline int hw_breakpoint_slots(int type)
{
return HBP_NUM;
}

/* arch/sh/kernel/hw_breakpoint.c */
extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
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 hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);

Expand Down
34 changes: 27 additions & 7 deletions trunk/arch/sh/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,26 @@ 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.
*/
int arch_check_bp_in_kernelspace(struct perf_event *bp)
static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len)
{
unsigned int len;
unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);

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

return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
}
Expand Down Expand Up @@ -217,7 +226,8 @@ 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)
int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
unsigned int align;
Expand Down Expand Up @@ -260,6 +270,15 @@ 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 @@ -344,7 +363,8 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
perf_bp_event(bp, args->regs);

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

info.si_signo = args->signr;
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/sh/kernel/ptrace_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ static int set_single_step(struct task_struct *tsk, unsigned long addr)

bp = thread->ptrace_bps[0];
if (!bp) {
ptrace_breakpoint_init(&attr);
hw_breakpoint_init(&attr);

attr.bp_addr = addr;
attr.bp_len = HW_BREAKPOINT_LEN_2;
Expand Down
1 change: 0 additions & 1 deletion trunk/arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ config X86
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_HW_BREAKPOINT
select HAVE_MIXED_BREAKPOINTS_REGS
select PERF_EVENTS
select ANON_INODES
select HAVE_ARCH_KMEMCHECK
Expand Down
10 changes: 3 additions & 7 deletions trunk/arch/x86/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,12 @@ struct arch_hw_breakpoint {
/* Total number of available HW breakpoint registers */
#define HBP_NUM 4

static inline int hw_breakpoint_slots(int type)
{
return HBP_NUM;
}

struct perf_event;
struct pmu;

extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
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 hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);

Expand Down
41 changes: 35 additions & 6 deletions trunk/arch/x86/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,17 +188,26 @@ 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.
*/
int arch_check_bp_in_kernelspace(struct perf_event *bp)
static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len)
{
unsigned int len;
unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);

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

return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
}
Expand Down Expand Up @@ -291,7 +300,8 @@ 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)
int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk)
{
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
unsigned int align;
Expand All @@ -304,6 +314,16 @@ 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 @@ -330,6 +350,15 @@ 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
2 changes: 1 addition & 1 deletion trunk/arch/x86/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
struct perf_event_attr attr;

if (!t->ptrace_bps[nr]) {
ptrace_breakpoint_init(&attr);
hw_breakpoint_init(&attr);
/*
* Put stub len and type to register (reserve) an inactive but
* correct bp
Expand Down
25 changes: 3 additions & 22 deletions trunk/include/linux/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,9 @@ enum {
};

enum {
HW_BREAKPOINT_EMPTY = 0,
HW_BREAKPOINT_R = 1,
HW_BREAKPOINT_W = 2,
HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W,
HW_BREAKPOINT_X = 4,
HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X,
};

enum bp_type_idx {
TYPE_INST = 0,
#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
TYPE_DATA = 0,
#else
TYPE_DATA = 1,
#endif
TYPE_MAX
HW_BREAKPOINT_R = 1,
HW_BREAKPOINT_W = 2,
HW_BREAKPOINT_X = 4,
};

#ifdef __KERNEL__
Expand All @@ -47,12 +34,6 @@ static inline void hw_breakpoint_init(struct perf_event_attr *attr)
attr->sample_period = 1;
}

static inline void ptrace_breakpoint_init(struct perf_event_attr *attr)
{
hw_breakpoint_init(attr);
attr->exclude_kernel = 1;
}

static inline unsigned long hw_breakpoint_addr(struct perf_event *bp)
{
return bp->attr.bp_addr;
Expand Down
Loading

0 comments on commit 7c52e8e

Please sign in to comment.