linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [BUG] perf stat: events inheritance can break task targets
@ 2014-07-07 16:41 Alexander Yarygin
  2014-07-07 17:00 ` Jiri Olsa
  0 siblings, 1 reply; 4+ messages in thread
From: Alexander Yarygin @ 2014-07-07 16:41 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Jiri Olsa
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Christian Borntraeger, linux-kernel

perf stat can block pthread_create() for a multithreaded userspace
process (i.e. qemu) when:
- process is running with non-root privileges
- perf stat is running as root with trace events in -e option
- it is attached to the process's pid.

Here is a simple test scenario:

~$ cat test.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>

#define THREADS 50

static pthread_t threads[THREADS];

void *loop()
{
    while(1);
}

int main()
{
    for (int i = 0; i < THREADS; i++) {

        int err = pthread_create(&threads[i], NULL, loop, 0);

        if (!err)
            printf("thread created: %i\n", i);
        else
            printf("couldn't create thread %i: %s\n", i, strerror(err));

        sleep(1);
    }

    return 0;
}
~$ gcc test.c -lpthread -std=c99 -o test
~$ ./test
thread created: 0
thread created: 1
# now perf is running:
# ~$ sudo perf stat -e "kvm:*" -p `pidof test`
couldn't create thread 2: Operation not permitted
couldn't create thread 3: Operation not permitted
couldn't create thread 4: Operation not permitted
# here is perf was stopped
thread created: 5
thread created: 6
^C

When perf is running, every invoke of pthread_create() returns -EPERM.

On the kernel side, copy_process() creates a task, scheduled it,
than perf_event_init_task() (kernel/events/core.c) returns an error,
and the kernel cleans task's resources.

It looks like child process doesn't have access to trace events,
so perf_trace_event_perm() (kernel/trace/trace_event_perf.c)
returns -EPERM:

static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
				 struct perf_event *p_event)
{
...
    /*
     * ...otherwise raw tracepoint data can be a severe data leak,
     * only allow root to have these.
     */
    if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
        return -EPERM;
...
}

If we explicitly use the --no-inherit option, payload wouldn't die.


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [BUG] perf stat: events inheritance can break task targets
  2014-07-07 16:41 [BUG] perf stat: events inheritance can break task targets Alexander Yarygin
@ 2014-07-07 17:00 ` Jiri Olsa
  2014-07-07 19:46   ` Peter Zijlstra
  0 siblings, 1 reply; 4+ messages in thread
From: Jiri Olsa @ 2014-07-07 17:00 UTC (permalink / raw)
  To: Alexander Yarygin
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Christian Borntraeger, linux-kernel

On Mon, Jul 07, 2014 at 08:41:57PM +0400, Alexander Yarygin wrote:

SNIP

> ^C
> 
> When perf is running, every invoke of pthread_create() returns -EPERM.
> 
> On the kernel side, copy_process() creates a task, scheduled it,
> than perf_event_init_task() (kernel/events/core.c) returns an error,
> and the kernel cleans task's resources.
> 
> It looks like child process doesn't have access to trace events,
> so perf_trace_event_perm() (kernel/trace/trace_event_perf.c)
> returns -EPERM:
> 
> static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
> 				 struct perf_event *p_event)
> {
> ...
>     /*
>      * ...otherwise raw tracepoint data can be a severe data leak,
>      * only allow root to have these.
>      */
>     if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
>         return -EPERM;
> ...
> }

right, so normaly it's done the check is done in current context
via syscall and the current task is the tracer

while in inheriting we are checking the tracee here,
we want to check the owner instead like in attached
patch.. totaly untested, just to ilustrate the point

we might have same issue for other event types

jirka


---
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 5d12bb4..b44184b 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -24,6 +24,9 @@ static int	total_ref_count;
 static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
 				 struct perf_event *p_event)
 {
+	struct task_struct owner = p_event->parent ? p_event->parent->owner :
+						     p_event->owner;
+
 	if (tp_event->perf_perm) {
 		int ret = tp_event->perf_perm(tp_event, p_event);
 		if (ret)
@@ -32,7 +35,7 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
 
 	/* The ftrace function trace is allowed only for root. */
 	if (ftrace_event_is_function(tp_event)) {
-		if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
+		if (perf_paranoid_tracepoint_raw() && !has_capability(owner, CAP_SYS_ADMIN))
 			return -EPERM;
 
 		/*
@@ -65,7 +68,7 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
 	 * ...otherwise raw tracepoint data can be a severe data leak,
 	 * only allow root to have these.
 	 */
-	if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
+	if (perf_paranoid_tracepoint_raw() && !has_capability(owner, CAP_SYS_ADMIN))
 		return -EPERM;
 
 	return 0;

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [BUG] perf stat: events inheritance can break task targets
  2014-07-07 17:00 ` Jiri Olsa
@ 2014-07-07 19:46   ` Peter Zijlstra
  2014-07-08  6:59     ` Jiri Olsa
  0 siblings, 1 reply; 4+ messages in thread
From: Peter Zijlstra @ 2014-07-07 19:46 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Alexander Yarygin, Arnaldo Carvalho de Melo, Paul Mackerras,
	Ingo Molnar, Christian Borntraeger, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1516 bytes --]

On Mon, Jul 07, 2014 at 07:00:40PM +0200, Jiri Olsa wrote:
> diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
> index 5d12bb4..b44184b 100644
> --- a/kernel/trace/trace_event_perf.c
> +++ b/kernel/trace/trace_event_perf.c
> @@ -24,6 +24,9 @@ static int	total_ref_count;
>  static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
>  				 struct perf_event *p_event)
>  {
> +	struct task_struct owner = p_event->parent ? p_event->parent->owner :
> +						     p_event->owner;
> +
>  	if (tp_event->perf_perm) {
>  		int ret = tp_event->perf_perm(tp_event, p_event);
>  		if (ret)
> @@ -32,7 +35,7 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
>  
>  	/* The ftrace function trace is allowed only for root. */
>  	if (ftrace_event_is_function(tp_event)) {
> -		if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
> +		if (perf_paranoid_tracepoint_raw() && !has_capability(owner, CAP_SYS_ADMIN))
>  			return -EPERM;
>  
>  		/*
> @@ -65,7 +68,7 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
>  	 * ...otherwise raw tracepoint data can be a severe data leak,
>  	 * only allow root to have these.
>  	 */
> -	if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
> +	if (perf_paranoid_tracepoint_raw() && !has_capability(owner, CAP_SYS_ADMIN))
>  		return -EPERM;
>  
>  	return 0;

You need to either hold rcu_read_lock() or otherwise ensure the owner is
still valid.

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [BUG] perf stat: events inheritance can break task targets
  2014-07-07 19:46   ` Peter Zijlstra
@ 2014-07-08  6:59     ` Jiri Olsa
  0 siblings, 0 replies; 4+ messages in thread
From: Jiri Olsa @ 2014-07-08  6:59 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Alexander Yarygin, Arnaldo Carvalho de Melo, Paul Mackerras,
	Ingo Molnar, Christian Borntraeger, linux-kernel

On Mon, Jul 07, 2014 at 09:46:35PM +0200, Peter Zijlstra wrote:
> On Mon, Jul 07, 2014 at 07:00:40PM +0200, Jiri Olsa wrote:
> > diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
> > index 5d12bb4..b44184b 100644
> > --- a/kernel/trace/trace_event_perf.c
> > +++ b/kernel/trace/trace_event_perf.c
> > @@ -24,6 +24,9 @@ static int	total_ref_count;
> >  static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
> >  				 struct perf_event *p_event)
> >  {
> > +	struct task_struct owner = p_event->parent ? p_event->parent->owner :
> > +						     p_event->owner;
> > +
> >  	if (tp_event->perf_perm) {
> >  		int ret = tp_event->perf_perm(tp_event, p_event);
> >  		if (ret)
> > @@ -32,7 +35,7 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
> >  
> >  	/* The ftrace function trace is allowed only for root. */
> >  	if (ftrace_event_is_function(tp_event)) {
> > -		if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
> > +		if (perf_paranoid_tracepoint_raw() && !has_capability(owner, CAP_SYS_ADMIN))
> >  			return -EPERM;
> >  
> >  		/*
> > @@ -65,7 +68,7 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
> >  	 * ...otherwise raw tracepoint data can be a severe data leak,
> >  	 * only allow root to have these.
> >  	 */
> > -	if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
> > +	if (perf_paranoid_tracepoint_raw() && !has_capability(owner, CAP_SYS_ADMIN))
> >  		return -EPERM;
> >  
> >  	return 0;
> 
> You need to either hold rcu_read_lock() or otherwise ensure the owner is
> still valid.

ok, I'll resend

thanks,
jirka

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-07-08  6:59 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-07 16:41 [BUG] perf stat: events inheritance can break task targets Alexander Yarygin
2014-07-07 17:00 ` Jiri Olsa
2014-07-07 19:46   ` Peter Zijlstra
2014-07-08  6:59     ` Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).