aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2008-01-30 13:32:03 +0100
committerIngo Molnar <mingo@elte.hu>2008-01-30 13:32:03 +0100
commitcba4b65d359268c40679ca75ac92c0b93cecf6de (patch)
tree95352d42a1a51338b08b88603cd4678297d56917
parente6ae5d9540727b0e2e5e2fbeb683c84671ed0a31 (diff)
x86, ptrace: add buffer size checks
Pass the buffer size for (most) ptrace commands that pass user-allocated buffers and check that size before accessing the buffer. Unfortunately, PTRACE_BTS_GET already uses all 4 parameters. Commands that access user buffers return the number of bytes or records read or written. Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/kernel/ptrace.c25
-rw-r--r--include/asm-x86/ptrace-abi.h14
2 files changed, 29 insertions, 10 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:
diff --git a/include/asm-x86/ptrace-abi.h b/include/asm-x86/ptrace-abi.h
index 32fe137822b..bcf67044754 100644
--- a/include/asm-x86/ptrace-abi.h
+++ b/include/asm-x86/ptrace-abi.h
@@ -99,13 +99,15 @@ struct ptrace_bts_config {
#define PTRACE_BTS_CONFIG 40
/* Configure branch trace recording.
- DATA is ignored, ADDR points to a struct ptrace_bts_config.
+ ADDR points to a struct ptrace_bts_config.
+ DATA gives the size of that buffer.
A new buffer is allocated, iff the size changes.
+ Returns the number of bytes read.
*/
#define PTRACE_BTS_STATUS 41
-/* Return the current configuration.
- DATA is ignored, ADDR points to a struct ptrace_bts_config
- that will contain the result.
+/* Return the current configuration in a struct ptrace_bts_config
+ pointed to by ADDR; DATA gives the size of that buffer.
+ Returns the number of bytes written.
*/
#define PTRACE_BTS_SIZE 42
/* Return the number of available BTS records.
@@ -123,8 +125,8 @@ struct ptrace_bts_config {
*/
#define PTRACE_BTS_DRAIN 45
/* Read all available BTS records and clear the buffer.
- DATA is ignored. ADDR points to an array of struct bts_struct of
- suitable size.
+ ADDR points to an array of struct bts_struct.
+ DATA gives the size of that buffer.
BTS records are read from oldest to newest.
Returns number of BTS records drained.
*/