ring-buffer: Bug fixes
Subsystems (3)
Steven Rostedt
maintainerIngo,
This is based off of my last urgent pull request.
Please pull the latest tip/perf/urgent-2 tree, which can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
tip/perf/urgent-2
Head SHA1: 9366c1ba13fbc41bdb57702e75ca4382f209c82f
Steven Rostedt (2):
ring-buffer: Fix NULL pointer if rb_set_head_page() fails
ring-buffer: Fix race between integrity check and readers
----
kernel/trace/ring_buffer.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
Steven Rostedt
maintainerPATCH 1/2 ring-buffer: Fix NULL pointer if rb_set_head_page() fails
From: Steven Rostedt <[email protected]>
The function rb_set_head_page() searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do a WARN_ON(), disable the ring buffer and return NULL, as this should never happen.
But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
--- kernel/trace/ring_buffer.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/trace/ring_buffer.c +7 -2
@@ -1396,6 +1396,8 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer)struct list_head *head_page_with_bit; head_page = &rb_set_head_page (cpu_buffer)->list; +if (!head_page) +break ; prev_page = head_page->prev; first_page = pages->next;
@@ -2934,7 +2936,7 @@ unsigned long ring_buffer_oldest_event_ts(struct ring_buffer *buffer, int cpu)unsigned long flags;struct ring_buffer_per_cpu *cpu_buffer;struct buffer_page *bpage; -unsigned long ret; +unsigned long ret =0 ;if (!cpumask_test_cpu (cpu, buffer->cpumask))return 0 ;
@@ -2949,7 +2951,8 @@ unsigned long ring_buffer_oldest_event_ts(struct ring_buffer *buffer, int cpu) bpage = cpu_buffer->reader_page; else bpage =rb_set_head_page (cpu_buffer); - ret = bpage->page->time_stamp; +if (bpage) + ret = bpage->page->time_stamp;raw_spin_unlock_irqrestore (&cpu_buffer->reader_lock, flags);return ret;
@@ -3260,6 +3263,8 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)* Splice the empty reader page into the list around the head. */ reader =rb_set_head_page (cpu_buffer); +if (!reader) + goto out; cpu_buffer->reader_page->list.next =rb_list_head (reader->list.next); cpu_buffer->reader_page->list.prev = reader->list.prev;
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerPATCH 1/2 ring-buffer: Fix NULL pointer if rb_set_head_page() fails
The function rb_set_head_page() searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do a WARN_ON(), disable the ring buffer and return NULL, as this should never happen.
But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
--- kernel/trace/ring_buffer.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)
kernel/trace/ring_buffer.c +2 -0
@@ -2926,6 +2926,8 @@ rb_get_reader_page(struct ring_buffer_pe* Splice the empty reader page into the list around the head. */ reader =rb_set_head_page (cpu_buffer); +if (!reader) + goto out; cpu_buffer->reader_page->list.next =rb_list_head (reader->list.next); cpu_buffer->reader_page->list.prev = reader->list.prev;
Re: [v3.0 stable version][PATCH 1/2] ring-buffer: Fix NULL pointer if rb_set_head_page() fails
Quoted 9 lines · Steven Rostedt
The function
rb_set_head_page()searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do aWARN_ON(), disable the ring buffer and return NULL, as this should never happen.But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
Quoted 5 lines
Cc [email protected] # 3.0+Signed-off-by Steven Rostedt <[email protected]>--- kernel/trace/ring_buffer.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)
I don't understand why you sent these to stable@ right now, I don't see them in Linus's tree, so why are they needed here?
Care to resend them when they hit Linus's tree?
thanks,
greg k-h
Steven Rostedt
maintainerRe: [v3.0 stable version][PATCH 1/2] ring-buffer: Fix NULL pointer if rb_set_head_page() fails
Quoted 10 lines · Greg KH
Quoted 9 lines · Steven Rostedt
The function
rb_set_head_page()searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do aWARN_ON(), disable the ring buffer and return NULL, as this should never happen.But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
Quoted 8 lines
Quoted 5 lines
Cc [email protected] # 3.0+Signed-off-by Steven Rostedt <[email protected]>--- kernel/trace/ring_buffer.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)I don't understand why you sent these to stable@ right now, I don't see them in Linus's tree, so why are they needed here?
Answer below.
Quoted 2 lines
Care to resend them when they hit Linus's tree?
I'll try to remember, but I will most likely forget :-)
I wrote the patches for each stable version while they were still fresh in my mind. I posted them so they would be there when they get into mainline and be easier to port for stable. By the time they are in mainline, they will be completely out of my mind :-)
Also, it seems that Ingo has been so busy with NUMA, that my patches have been forgotten about. I may have to push to Linus directly :-/
-- Steve
Re: [v3.0 stable version][PATCH 1/2] ring-buffer: Fix NULL pointer if rb_set_head_page() fails
Quoted 23 lines · Steven Rostedt
Quoted 10 lines · Greg KH
Quoted 9 lines · Steven Rostedt
The function
rb_set_head_page()searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do aWARN_ON(), disable the ring buffer and return NULL, as this should never happen.But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
Quoted 8 lines
Quoted 5 lines
Cc [email protected] # 3.0+Signed-off-by Steven Rostedt <[email protected]>--- kernel/trace/ring_buffer.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)I don't understand why you sent these to stable@ right now, I don't see them in Linus's tree, so why are they needed here?
Answer below.
Quoted 1 line
Quoted 8 lines
Quoted 1 line
Care to resend them when they hit Linus's tree?
I'll try to remember, but I will most likely forget :-)
I wrote the patches for each stable version while they were still fresh in my mind. I posted them so they would be there when they get into mainline and be easier to port for stable. By the time they are in mainline, they will be completely out of my mind :-)
Ok, if they are that important, consider them forgotten from my mind as well :)
greg k-h
Steven Rostedt
maintainerPATCH 1/2 ring-buffer: Fix NULL pointer if rb_set_head_page() fails
In reply to Steven RostedtThe function rb_set_head_page() searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do a WARN_ON(), disable the ring buffer and return NULL, as this should never happen.
But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
--- kernel/trace/ring_buffer.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)
kernel/trace/ring_buffer.c +5 -2
@@ -2683,7 +2683,7 @@ unsigned long ring_buffer_oldest_event_tunsigned long flags;struct ring_buffer_per_cpu *cpu_buffer;struct buffer_page *bpage; -unsigned long ret; +unsigned long ret =0 ;if (!cpumask_test_cpu (cpu, buffer->cpumask))return 0 ;
@@ -2698,7 +2698,8 @@ unsigned long ring_buffer_oldest_event_t bpage = cpu_buffer->reader_page; else bpage =rb_set_head_page (cpu_buffer); - ret = bpage->page->time_stamp; +if (bpage) + ret = bpage->page->time_stamp;raw_spin_unlock_irqrestore (&cpu_buffer->reader_lock, flags);return ret;
@@ -3005,6 +3006,8 @@ rb_get_reader_page(struct ring_buffer_pe* Splice the empty reader page into the list around the head. */ reader =rb_set_head_page (cpu_buffer); +if (!reader) + goto out; cpu_buffer->reader_page->list.next =rb_list_head (reader->list.next); cpu_buffer->reader_page->list.prev = reader->list.prev;
Re: [v3.2-v3.4 stable version][PATCH 1/2] ring-buffer: Fix NULL pointer if rb_set_head_page() fails
Quoted 11 lines · Steven Rostedt
The function
rb_set_head_page()searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do aWARN_ON(), disable the ring buffer and return NULL, as this should never happen.But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
Cc [email protected] # 3.0+Signed-off-by Steven Rostedt <[email protected]>
[...]
Added to the queue for 3.2, thanks.
Ben.
Signature · 2 lines
Ben Hutchings The world is coming to an end. Please log off.
Steven Rostedt
maintainerRe: [PATCH 1/2] ring-buffer: Fix NULL pointer if rb_set_head_page() fails
In reply to Steven RostedtQuoted 7 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
The function
rb_set_head_page()searches the list of ring buffer pages for a the page that has the HEAD page flag set. If it does not find it, it will do aWARN_ON(), disable the ring buffer and return NULL, as this should never happen.
Quoted 5 lines
But if this bug happens to happen, not all callers of this function can handle a NULL pointer being returned from it. That needs to be fixed.
Cc [email protected] # 3.0+
Hmm, quilt didn't Cc. Grumble, I think a system update of quilt removed my modification to not have quilt get confused by the hash symbol :-(
-- Steve
Quoted 46 lines
Signed-off-by Steven Rostedt <[email protected]>--- kernel/trace/ring_buffer.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)kernel/trace/ring_buffer.c +7
-2@@ -1396,6 +1396,8 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer)struct list_head *head_page_with_bit; head_page = &rb_set_head_page (cpu_buffer)->list; +if (!head_page) +break ; prev_page = head_page->prev; first_page = pages->next;@@ -2934,7 +2936,7 @@ unsigned long ring_buffer_oldest_event_ts(struct ring_buffer *buffer, int cpu)unsigned long flags;struct ring_buffer_per_cpu *cpu_buffer;struct buffer_page *bpage; -unsigned long ret; +unsigned long ret =0 ;if (!cpumask_test_cpu (cpu, buffer->cpumask))return 0 ;@@ -2949,7 +2951,8 @@ unsigned long ring_buffer_oldest_event_ts(struct ring_buffer *buffer, int cpu) bpage = cpu_buffer->reader_page; else bpage =rb_set_head_page (cpu_buffer); - ret = bpage->page->time_stamp; +if (bpage) + ret = bpage->page->time_stamp;raw_spin_unlock_irqrestore (&cpu_buffer->reader_lock, flags);return ret;@@ -3260,6 +3263,8 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)* Splice the empty reader page into the list around the head. */ reader =rb_set_head_page (cpu_buffer); +if (!reader) + goto out; cpu_buffer->reader_page->list.next =rb_list_head (reader->list.next); cpu_buffer->reader_page->list.prev = reader->list.prev;
Steven Rostedt
maintainerPATCH 2/2 ring-buffer: Fix race between integrity check and readers
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
The function rb_check_pages() was added to make sure the ring buffer's pages were sane. This check is done when the ring buffer size is modified as well as when the iterator is released (closing the "trace" file), as that was considered a non fast path and a good place to do a sanity check.
The problem is that the check does not have any locks around it. If one process were to read the trace file, and another were to read the raw binary file, the check could happen while the reader is reading the file.
The issues with this is that the check requires to clear the HEAD page before doing the full check and it restores it afterward. But readers require the HEAD page to exist before it can read the buffer, otherwise it gives a nasty warning and disables the buffer.
By adding the reader lock around the check, this keeps the race from happening.
--- kernel/trace/ring_buffer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
kernel/trace/ring_buffer.c +6 -1
@@ -3783,12 +3783,17 @@ void ring_buffer_read_finish(struct ring_buffer_iter *iter) {struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; +unsigned long flags;/* * Ring buffer is disabled from recording, here's a good place -* to check the integrity of the ring buffer. +* to check the integrity of the ring buffer. +* Must prevent readers from trying to read, as the check +* clears the HEAD page and readers require it. */ +raw_spin_lock_irqsave (&cpu_buffer->reader_lock, flags);rb_check_pages (cpu_buffer); +raw_spin_unlock_irqrestore (&cpu_buffer->reader_lock, flags);atomic_dec (&cpu_buffer->record_disabled);atomic_dec (&cpu_buffer->buffer->resize_disabled);
Signature · 1 line
1.7.10.4
Steven Rostedt
maintainerRe: [PATCH 2/2] ring-buffer: Fix race between integrity check and readers
Quoted 18 lines · Steven Rostedt
From: Steven Rostedt <[email protected]>
The function
rb_check_pages()was added to make sure the ring buffer's pages were sane. This check is done when the ring buffer size is modified as well as when the iterator is released (closing the "trace" file), as that was considered a non fast path and a good place to do a sanity check.The problem is that the check does not have any locks around it. If one process were to read the trace file, and another were to read the raw binary file, the check could happen while the reader is reading the file.
The issues with this is that the check requires to clear the HEAD page before doing the full check and it restores it afterward. But readers require the HEAD page to exist before it can read the buffer, otherwise it gives a nasty warning and disables the buffer.
Quoted 4 lines
By adding the reader lock around the check, this keeps the race from happening.
Cc [email protected] # 3.6
Again, quilt failed to Cc stable :-(
-- Steve
Quoted 28 lines
Signed-off-by Steven Rostedt <[email protected]>--- kernel/trace/ring_buffer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)kernel/trace/ring_buffer.c +6
-1@@ -3783,12 +3783,17 @@ void ring_buffer_read_finish(struct ring_buffer_iter *iter) {struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; +unsigned long flags;/* * Ring buffer is disabled from recording, here's a good place -* to check the integrity of the ring buffer. +* to check the integrity of the ring buffer. +* Must prevent readers from trying to read, as the check +* clears the HEAD page and readers require it. */ +raw_spin_lock_irqsave (&cpu_buffer->reader_lock, flags);rb_check_pages (cpu_buffer); +raw_spin_unlock_irqrestore (&cpu_buffer->reader_lock, flags);atomic_dec (&cpu_buffer->record_disabled);atomic_dec (&cpu_buffer->buffer->resize_disabled);
Quoted 13 lines · Steven Rostedt
Ingo,
This is based off of my last urgent pull request.
Please pull the latest tip/perf/urgent-2 tree, which can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
tip/perf/urgent-2Head SHA1:
9366c1ba13fbc41bdb57702e75ca4382f209c82f
Quoted 7 lines
Steven Rostedt (2):
ring-buffer: Fix NULL pointer ifrb_set_head_page()fails
ring-buffer: Fix race between integrity check and readers----
kernel/trace/ring_buffer.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
Pulled, thanks Steve!
Ingo