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>
This commit is contained in:
parent
e6ae5d9540
commit
cba4b65d35
|
@ -591,6 +591,7 @@ static int ptrace_bts_clear(struct task_struct *child)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ptrace_bts_drain(struct task_struct *child,
|
static int ptrace_bts_drain(struct task_struct *child,
|
||||||
|
long size,
|
||||||
struct bts_struct __user *out)
|
struct bts_struct __user *out)
|
||||||
{
|
{
|
||||||
int end, i;
|
int end, i;
|
||||||
|
@ -603,6 +604,9 @@ static int ptrace_bts_drain(struct task_struct *child,
|
||||||
if (end <= 0)
|
if (end <= 0)
|
||||||
return end;
|
return end;
|
||||||
|
|
||||||
|
if (size < (end * sizeof(struct bts_struct)))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
for (i = 0; i < end; i++, out++) {
|
for (i = 0; i < end; i++, out++) {
|
||||||
struct bts_struct ret;
|
struct bts_struct ret;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -617,7 +621,7 @@ static int ptrace_bts_drain(struct task_struct *child,
|
||||||
|
|
||||||
ds_clear(ds);
|
ds_clear(ds);
|
||||||
|
|
||||||
return i;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ptrace_bts_realloc(struct task_struct *child,
|
static int ptrace_bts_realloc(struct task_struct *child,
|
||||||
|
@ -690,15 +694,22 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ptrace_bts_config(struct task_struct *child,
|
static int ptrace_bts_config(struct task_struct *child,
|
||||||
|
long cfg_size,
|
||||||
const struct ptrace_bts_config __user *ucfg)
|
const struct ptrace_bts_config __user *ucfg)
|
||||||
{
|
{
|
||||||
struct ptrace_bts_config cfg;
|
struct ptrace_bts_config cfg;
|
||||||
int bts_size, ret = 0;
|
int bts_size, ret = 0;
|
||||||
void *ds;
|
void *ds;
|
||||||
|
|
||||||
|
if (cfg_size < sizeof(cfg))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
|
if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
if ((int)cfg.size < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
bts_size = 0;
|
bts_size = 0;
|
||||||
ds = (void *)child->thread.ds_area_msr;
|
ds = (void *)child->thread.ds_area_msr;
|
||||||
if (ds) {
|
if (ds) {
|
||||||
|
@ -734,6 +745,8 @@ static int ptrace_bts_config(struct task_struct *child,
|
||||||
else
|
else
|
||||||
clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
|
clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
|
||||||
|
|
||||||
|
ret = sizeof(cfg);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (child->thread.debugctlmsr)
|
if (child->thread.debugctlmsr)
|
||||||
set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
|
set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
|
||||||
|
@ -749,11 +762,15 @@ errout:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ptrace_bts_status(struct task_struct *child,
|
static int ptrace_bts_status(struct task_struct *child,
|
||||||
|
long cfg_size,
|
||||||
struct ptrace_bts_config __user *ucfg)
|
struct ptrace_bts_config __user *ucfg)
|
||||||
{
|
{
|
||||||
void *ds = (void *)child->thread.ds_area_msr;
|
void *ds = (void *)child->thread.ds_area_msr;
|
||||||
struct ptrace_bts_config cfg;
|
struct ptrace_bts_config cfg;
|
||||||
|
|
||||||
|
if (cfg_size < sizeof(cfg))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
|
|
||||||
if (ds) {
|
if (ds) {
|
||||||
|
@ -923,12 +940,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||||
|
|
||||||
case PTRACE_BTS_CONFIG:
|
case PTRACE_BTS_CONFIG:
|
||||||
ret = ptrace_bts_config
|
ret = ptrace_bts_config
|
||||||
(child, (struct ptrace_bts_config __user *)addr);
|
(child, data, (struct ptrace_bts_config __user *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PTRACE_BTS_STATUS:
|
case PTRACE_BTS_STATUS:
|
||||||
ret = ptrace_bts_status
|
ret = ptrace_bts_status
|
||||||
(child, (struct ptrace_bts_config __user *)addr);
|
(child, data, (struct ptrace_bts_config __user *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PTRACE_BTS_SIZE:
|
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:
|
case PTRACE_BTS_DRAIN:
|
||||||
ret = ptrace_bts_drain
|
ret = ptrace_bts_drain
|
||||||
(child, (struct bts_struct __user *) addr);
|
(child, data, (struct bts_struct __user *) addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -99,13 +99,15 @@ struct ptrace_bts_config {
|
||||||
|
|
||||||
#define PTRACE_BTS_CONFIG 40
|
#define PTRACE_BTS_CONFIG 40
|
||||||
/* Configure branch trace recording.
|
/* 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.
|
A new buffer is allocated, iff the size changes.
|
||||||
|
Returns the number of bytes read.
|
||||||
*/
|
*/
|
||||||
#define PTRACE_BTS_STATUS 41
|
#define PTRACE_BTS_STATUS 41
|
||||||
/* Return the current configuration.
|
/* Return the current configuration in a struct ptrace_bts_config
|
||||||
DATA is ignored, ADDR points to a struct ptrace_bts_config
|
pointed to by ADDR; DATA gives the size of that buffer.
|
||||||
that will contain the result.
|
Returns the number of bytes written.
|
||||||
*/
|
*/
|
||||||
#define PTRACE_BTS_SIZE 42
|
#define PTRACE_BTS_SIZE 42
|
||||||
/* Return the number of available BTS records.
|
/* Return the number of available BTS records.
|
||||||
|
@ -123,8 +125,8 @@ struct ptrace_bts_config {
|
||||||
*/
|
*/
|
||||||
#define PTRACE_BTS_DRAIN 45
|
#define PTRACE_BTS_DRAIN 45
|
||||||
/* Read all available BTS records and clear the buffer.
|
/* Read all available BTS records and clear the buffer.
|
||||||
DATA is ignored. ADDR points to an array of struct bts_struct of
|
ADDR points to an array of struct bts_struct.
|
||||||
suitable size.
|
DATA gives the size of that buffer.
|
||||||
BTS records are read from oldest to newest.
|
BTS records are read from oldest to newest.
|
||||||
Returns number of BTS records drained.
|
Returns number of BTS records drained.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue