2014-11-08 15:14:46

by Arianna Avanzini

[permalink] [raw]
Subject: [PATCH RFC] trace, blktrace: remove trace from running list only if trace is running

Currently, blktrace can be started/stopped via its ioctl-based interface
(used by the userspace blktrace tool) or via its ftrace interface. The
function blk_trace_remove_queue(), called each time an "enable" tunable
of the ftrace interface transitions to zero, removes unconditionally the
trace from the running list, even if its state is not Blktrace_running.
In fact, the state of a blk_trace is modified only by the ioctl-based
interface, and a blk_trace is added to the running list only when its
state transitions from Blktrace_setup or Blktrace_stopped to
Blktrace_running. If the ioctl-based interface is not being used, the
state of the blk_trace is undefined.
In this case, using the sysfs tunable to stop a trace would trigger a
removal of a blk_trace from the running list while it is not on such a
list, leading to a null pointer dereference. This commit attempts to fix
the issue by letting the blk_trace_remove_queue() function remove the
blk_trace from the running list only if its state is Blktrace_running.

Signed-off-by: Arianna Avanzini <[email protected]>
---
kernel/trace/blktrace.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index c1bd4ad..f58b617 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -1493,9 +1493,11 @@ static int blk_trace_remove_queue(struct request_queue *q)
if (atomic_dec_and_test(&blk_probes_ref))
blk_unregister_tracepoints();

- spin_lock_irq(&running_trace_lock);
- list_del(&bt->running_list);
- spin_unlock_irq(&running_trace_lock);
+ if (bt->trace_state == Blktrace_running) {
+ spin_lock_irq(&running_trace_lock);
+ list_del(&bt->running_list);
+ spin_unlock_irq(&running_trace_lock);
+ }
blk_trace_free(bt);
return 0;
}
--
2.1.2


2014-11-10 08:25:59

by Namhyung Kim

[permalink] [raw]
Subject: Re: [PATCH RFC] trace, blktrace: remove trace from running list only if trace is running

Hi Arianna,

On Sat, 8 Nov 2014 16:14:40 +0100, Arianna Avanzini wrote:
> Currently, blktrace can be started/stopped via its ioctl-based interface
> (used by the userspace blktrace tool) or via its ftrace interface. The
> function blk_trace_remove_queue(), called each time an "enable" tunable
> of the ftrace interface transitions to zero, removes unconditionally the
> trace from the running list, even if its state is not Blktrace_running.
> In fact, the state of a blk_trace is modified only by the ioctl-based
> interface, and a blk_trace is added to the running list only when its
> state transitions from Blktrace_setup or Blktrace_stopped to
> Blktrace_running. If the ioctl-based interface is not being used, the
> state of the blk_trace is undefined.
> In this case, using the sysfs tunable to stop a trace would trigger a
> removal of a blk_trace from the running list while it is not on such a
> list, leading to a null pointer dereference. This commit attempts to fix
> the issue by letting the blk_trace_remove_queue() function remove the
> blk_trace from the running list only if its state is Blktrace_running.

What about just getting rid of the list_del()? blk_trace_setup_queue()
doesn't add it to running_trace_list and I think we should prevent mix
of ioctl and sysfs usage somehow..

Thanks,
Namhyung


>
> Signed-off-by: Arianna Avanzini <[email protected]>
> ---
> kernel/trace/blktrace.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
> index c1bd4ad..f58b617 100644
> --- a/kernel/trace/blktrace.c
> +++ b/kernel/trace/blktrace.c
> @@ -1493,9 +1493,11 @@ static int blk_trace_remove_queue(struct request_queue *q)
> if (atomic_dec_and_test(&blk_probes_ref))
> blk_unregister_tracepoints();
>
> - spin_lock_irq(&running_trace_lock);
> - list_del(&bt->running_list);
> - spin_unlock_irq(&running_trace_lock);
> + if (bt->trace_state == Blktrace_running) {
> + spin_lock_irq(&running_trace_lock);
> + list_del(&bt->running_list);
> + spin_unlock_irq(&running_trace_lock);
> + }
> blk_trace_free(bt);
> return 0;
> }

2014-11-10 10:40:51

by Arianna Avanzini

[permalink] [raw]
Subject: Re: [PATCH RFC] trace, blktrace: remove trace from running list only if trace is running

On Mon, Nov 10, 2014 at 05:25:56PM +0900, Namhyung Kim wrote:
> Hi Arianna,

Hi Namhyung,

thank you for replying.

>
> On Sat, 8 Nov 2014 16:14:40 +0100, Arianna Avanzini wrote:
> > Currently, blktrace can be started/stopped via its ioctl-based interface
> > (used by the userspace blktrace tool) or via its ftrace interface. The
> > function blk_trace_remove_queue(), called each time an "enable" tunable
> > of the ftrace interface transitions to zero, removes unconditionally the
> > trace from the running list, even if its state is not Blktrace_running.
> > In fact, the state of a blk_trace is modified only by the ioctl-based
> > interface, and a blk_trace is added to the running list only when its
> > state transitions from Blktrace_setup or Blktrace_stopped to
> > Blktrace_running. If the ioctl-based interface is not being used, the
> > state of the blk_trace is undefined.
> > In this case, using the sysfs tunable to stop a trace would trigger a
> > removal of a blk_trace from the running list while it is not on such a
> > list, leading to a null pointer dereference. This commit attempts to fix
> > the issue by letting the blk_trace_remove_queue() function remove the
> > blk_trace from the running list only if its state is Blktrace_running.
>
> What about just getting rid of the list_del()? blk_trace_setup_queue()
> doesn't add it to running_trace_list and I think we should prevent mix
> of ioctl and sysfs usage somehow..
>

And blk_trace_remove_queue() is used only by the sysfs interface, you're
right. I'm re-sending the patch with your comment applied.

Thank you,
Arianna


> Thanks,
> Namhyung
>
>
> >
> > Signed-off-by: Arianna Avanzini <[email protected]>
> > ---
> > kernel/trace/blktrace.c | 8 +++++---
> > 1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
> > index c1bd4ad..f58b617 100644
> > --- a/kernel/trace/blktrace.c
> > +++ b/kernel/trace/blktrace.c
> > @@ -1493,9 +1493,11 @@ static int blk_trace_remove_queue(struct request_queue *q)
> > if (atomic_dec_and_test(&blk_probes_ref))
> > blk_unregister_tracepoints();
> >
> > - spin_lock_irq(&running_trace_lock);
> > - list_del(&bt->running_list);
> > - spin_unlock_irq(&running_trace_lock);
> > + if (bt->trace_state == Blktrace_running) {
> > + spin_lock_irq(&running_trace_lock);
> > + list_del(&bt->running_list);
> > + spin_unlock_irq(&running_trace_lock);
> > + }
> > blk_trace_free(bt);
> > return 0;
> > }

--
/*
* Arianna Avanzini
* [email protected]
* http://ava.webhop.me
*/

2014-11-10 10:40:57

by Arianna Avanzini

[permalink] [raw]
Subject: [PATCH RFC v2] trace, blktrace: don't let the sysfs interface remove trace from running list

Currently, blktrace can be started/stopped via its ioctl-based interface
(used by the userspace blktrace tool) or via its ftrace interface. The
function blk_trace_remove_queue(), called each time an "enable" tunable
of the ftrace interface transitions to zero, removes the trace from the
running list, even if no function from the sysfs interface adds it to
such a list. This leads to a null pointer dereference.
This commit changes the blk_trace_remove_queue() function so that it
does not remove the blk_trace from the running list.

v2:
- Now the patch removes the invocation of list_del() instead of
adding an useless if branch, as suggested by Namhyung Kim.

Signed-off-by: Arianna Avanzini <[email protected]>
---
kernel/trace/blktrace.c | 3 ---
1 file changed, 3 deletions(-)

diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index c1bd4ad..bd05fd2 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -1493,9 +1493,6 @@ static int blk_trace_remove_queue(struct request_queue *q)
if (atomic_dec_and_test(&blk_probes_ref))
blk_unregister_tracepoints();

- spin_lock_irq(&running_trace_lock);
- list_del(&bt->running_list);
- spin_unlock_irq(&running_trace_lock);
blk_trace_free(bt);
return 0;
}
--
2.1.2

2014-11-14 02:07:50

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH RFC v2] trace, blktrace: don't let the sysfs interface remove trace from running list


Jens (Cc'd) maintains the blktrace. He can take this if he wants.

-- Steve


On Mon, 10 Nov 2014 11:40:49 +0100
Arianna Avanzini <[email protected]> wrote:

> Currently, blktrace can be started/stopped via its ioctl-based interface
> (used by the userspace blktrace tool) or via its ftrace interface. The
> function blk_trace_remove_queue(), called each time an "enable" tunable
> of the ftrace interface transitions to zero, removes the trace from the
> running list, even if no function from the sysfs interface adds it to
> such a list. This leads to a null pointer dereference.
> This commit changes the blk_trace_remove_queue() function so that it
> does not remove the blk_trace from the running list.
>
> v2:
> - Now the patch removes the invocation of list_del() instead of
> adding an useless if branch, as suggested by Namhyung Kim.
>
> Signed-off-by: Arianna Avanzini <[email protected]>
> ---
> kernel/trace/blktrace.c | 3 ---
> 1 file changed, 3 deletions(-)
>
> diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
> index c1bd4ad..bd05fd2 100644
> --- a/kernel/trace/blktrace.c
> +++ b/kernel/trace/blktrace.c
> @@ -1493,9 +1493,6 @@ static int blk_trace_remove_queue(struct request_queue *q)
> if (atomic_dec_and_test(&blk_probes_ref))
> blk_unregister_tracepoints();
>
> - spin_lock_irq(&running_trace_lock);
> - list_del(&bt->running_list);
> - spin_unlock_irq(&running_trace_lock);
> blk_trace_free(bt);
> return 0;
> }

2014-12-09 22:00:06

by Jens Axboe

[permalink] [raw]
Subject: Re: [PATCH RFC v2] trace, blktrace: don't let the sysfs interface remove trace from running list

On 11/13/2014 07:07 PM, Steven Rostedt wrote:
>
> Jens (Cc'd) maintains the blktrace. He can take this if he wants.
>
> -- Steve
>
>
> On Mon, 10 Nov 2014 11:40:49 +0100
> Arianna Avanzini <[email protected]> wrote:
>
>> Currently, blktrace can be started/stopped via its ioctl-based interface
>> (used by the userspace blktrace tool) or via its ftrace interface. The
>> function blk_trace_remove_queue(), called each time an "enable" tunable
>> of the ftrace interface transitions to zero, removes the trace from the
>> running list, even if no function from the sysfs interface adds it to
>> such a list. This leads to a null pointer dereference.
>> This commit changes the blk_trace_remove_queue() function so that it
>> does not remove the blk_trace from the running list.
>>
>> v2:
>> - Now the patch removes the invocation of list_del() instead of
>> adding an useless if branch, as suggested by Namhyung Kim.
>>
>> Signed-off-by: Arianna Avanzini <[email protected]>
>> ---
>> kernel/trace/blktrace.c | 3 ---
>> 1 file changed, 3 deletions(-)
>>
>> diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
>> index c1bd4ad..bd05fd2 100644
>> --- a/kernel/trace/blktrace.c
>> +++ b/kernel/trace/blktrace.c
>> @@ -1493,9 +1493,6 @@ static int blk_trace_remove_queue(struct request_queue *q)
>> if (atomic_dec_and_test(&blk_probes_ref))
>> blk_unregister_tracepoints();
>>
>> - spin_lock_irq(&running_trace_lock);
>> - list_del(&bt->running_list);
>> - spin_unlock_irq(&running_trace_lock);
>> blk_trace_free(bt);
>> return 0;

Applied, thanks!

--
Jens Axboe