Skip to content

Commit

Permalink
x86, ptrace: rlimit BTS buffer allocation
Browse files Browse the repository at this point in the history
Check the rlimit of the tracing task for total and locked memory when allocating the BTS buffer.

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>
  • Loading branch information
Markus Metzger authored and Ingo Molnar committed Jan 30, 2008
1 parent 59e87cd commit da35c37
Showing 1 changed file with 103 additions and 46 deletions.
149 changes: 103 additions & 46 deletions arch/x86/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,12 +620,80 @@ static int ptrace_bts_drain(struct task_struct *child,
return i;
}

static int ptrace_bts_realloc(struct task_struct *child,
int size, int reduce_size)
{
unsigned long rlim, vm;
int ret, old_size;

if (size < 0)
return -EINVAL;

old_size = ds_get_bts_size((void *)child->thread.ds_area_msr);
if (old_size < 0)
return old_size;

ret = ds_free((void **)&child->thread.ds_area_msr);
if (ret < 0)
goto out;

size >>= PAGE_SHIFT;
old_size >>= PAGE_SHIFT;

current->mm->total_vm -= old_size;
current->mm->locked_vm -= old_size;

if (size == 0)
goto out;

rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
vm = current->mm->total_vm + size;
if (rlim < vm) {
ret = -ENOMEM;

if (!reduce_size)
goto out;

size = rlim - current->mm->total_vm;
if (size <= 0)
goto out;
}

rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
vm = current->mm->locked_vm + size;
if (rlim < vm) {
ret = -ENOMEM;

if (!reduce_size)
goto out;

size = rlim - current->mm->locked_vm;
if (size <= 0)
goto out;
}

ret = ds_allocate((void **)&child->thread.ds_area_msr,
size << PAGE_SHIFT);
if (ret < 0)
goto out;

current->mm->total_vm += size;
current->mm->locked_vm += size;

out:
if (child->thread.ds_area_msr)
set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
else
clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);

return ret;
}

static int ptrace_bts_config(struct task_struct *child,
const struct ptrace_bts_config __user *ucfg)
{
struct ptrace_bts_config cfg;
unsigned long debugctl_mask;
int bts_size, ret;
int bts_size, ret = 0;
void *ds;

if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
Expand All @@ -638,59 +706,46 @@ static int ptrace_bts_config(struct task_struct *child,
if (bts_size < 0)
return bts_size;
}
cfg.size = PAGE_ALIGN(cfg.size);

if (bts_size != cfg.size) {
ret = ds_free((void **)&child->thread.ds_area_msr);
ret = ptrace_bts_realloc(child, cfg.size,
cfg.flags & PTRACE_BTS_O_CUT_SIZE);
if (ret < 0)
return ret;
goto errout;

if (cfg.size > 0)
ret = ds_allocate((void **)&child->thread.ds_area_msr,
cfg.size);
ds = (void *)child->thread.ds_area_msr;
if (ds)
set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
else
clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);

if (ret < 0)
return ret;

bts_size = ds_get_bts_size(ds);
if (bts_size <= 0)
return bts_size;
}

if (ds) {
if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
ret = ds_set_overflow(ds, DS_O_SIGNAL);
} else {
ret = ds_set_overflow(ds, DS_O_WRAP);
}
if (ret < 0)
return ret;
}

debugctl_mask = ds_debugctl_mask();
if (ds && (cfg.flags & PTRACE_BTS_O_TRACE)) {
child->thread.debugctlmsr |= debugctl_mask;
set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
} else {
/* there is no way for us to check whether we 'own'
* the respective bits in the DEBUGCTL MSR, we're
* about to clear */
child->thread.debugctlmsr &= ~debugctl_mask;
if (cfg.flags & PTRACE_BTS_O_SIGNAL)
ret = ds_set_overflow(ds, DS_O_SIGNAL);
else
ret = ds_set_overflow(ds, DS_O_WRAP);
if (ret < 0)
goto errout;

if (!child->thread.debugctlmsr)
clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
}
if (cfg.flags & PTRACE_BTS_O_TRACE)
child->thread.debugctlmsr |= ds_debugctl_mask();
else
child->thread.debugctlmsr &= ~ds_debugctl_mask();

if (ds && (cfg.flags & PTRACE_BTS_O_SCHED))
if (cfg.flags & PTRACE_BTS_O_SCHED)
set_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
else
clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);

return 0;
out:
if (child->thread.debugctlmsr)
set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
else
clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);

return ret;

errout:
child->thread.debugctlmsr &= ~ds_debugctl_mask();
clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
goto out;
}

static int ptrace_bts_status(struct task_struct *child,
Expand Down Expand Up @@ -726,7 +781,7 @@ void ptrace_bts_take_timestamp(struct task_struct *tsk,
{
struct bts_struct rec = {
.qualifier = qualifier,
.variant.jiffies = jiffies
.variant.jiffies = jiffies_64
};

ptrace_bts_write_record(tsk, &rec);
Expand All @@ -743,10 +798,12 @@ void ptrace_disable(struct task_struct *child)
#ifdef TIF_SYSCALL_EMU
clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
#endif
ptrace_bts_config(child, /* options = */ 0);
if (child->thread.ds_area_msr) {
ds_free((void **)&child->thread.ds_area_msr);
clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
ptrace_bts_realloc(child, 0, 0);
child->thread.debugctlmsr &= ~ds_debugctl_mask();
if (!child->thread.debugctlmsr)
clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
}
}

Expand Down

0 comments on commit da35c37

Please sign in to comment.