diff options
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 236528bec6e..e19a91db9b3 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -591,6 +591,7 @@ static int ptrace_bts_clear(struct task_struct *child) } static int ptrace_bts_drain(struct task_struct *child, + long size, struct bts_struct __user *out) { int end, i; @@ -603,6 +604,9 @@ static int ptrace_bts_drain(struct task_struct *child, if (end <= 0) return end; + if (size < (end * sizeof(struct bts_struct))) + return -EIO; + for (i = 0; i < end; i++, out++) { struct bts_struct ret; int retval; @@ -617,7 +621,7 @@ static int ptrace_bts_drain(struct task_struct *child, ds_clear(ds); - return i; + return end; } static int ptrace_bts_realloc(struct task_struct *child, @@ -690,15 +694,22 @@ out: } static int ptrace_bts_config(struct task_struct *child, + long cfg_size, const struct ptrace_bts_config __user *ucfg) { struct ptrace_bts_config cfg; int bts_size, ret = 0; void *ds; + if (cfg_size < sizeof(cfg)) + return -EIO; + if (copy_from_user(&cfg, ucfg, sizeof(cfg))) return -EFAULT; + if ((int)cfg.size < 0) + return -EINVAL; + bts_size = 0; ds = (void *)child->thread.ds_area_msr; if (ds) { @@ -734,6 +745,8 @@ static int ptrace_bts_config(struct task_struct *child, else clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS); + ret = sizeof(cfg); + out: if (child->thread.debugctlmsr) set_tsk_thread_flag(child, TIF_DEBUGCTLMSR); @@ -749,11 +762,15 @@ errout: } static int ptrace_bts_status(struct task_struct *child, + long cfg_size, struct ptrace_bts_config __user *ucfg) { void *ds = (void *)child->thread.ds_area_msr; struct ptrace_bts_config cfg; + if (cfg_size < sizeof(cfg)) + return -EIO; + memset(&cfg, 0, sizeof(cfg)); if (ds) { @@ -923,12 +940,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_BTS_CONFIG: ret = ptrace_bts_config - (child, (struct ptrace_bts_config __user *)addr); + (child, data, (struct ptrace_bts_config __user *)addr); break; case PTRACE_BTS_STATUS: ret = ptrace_bts_status - (child, (struct ptrace_bts_config __user *)addr); + (child, data, (struct ptrace_bts_config __user *)addr); break; case PTRACE_BTS_SIZE: @@ -946,7 +963,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_BTS_DRAIN: ret = ptrace_bts_drain - (child, (struct bts_struct __user *) addr); + (child, data, (struct bts_struct __user *) addr); break; default: |