summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2016-05-13 09:34:12 -0400
committerjenkins_ndg <jenkins_ndg@intel.com>2017-01-09 00:46:21 -0800
commitb654cc025fc36c9487d9f2aa33c23a99d43706c4 (patch)
tree84a9202abe6bdeded744e97e21a19d6f814eb84a
parent15dddfb7c00d747b9ffe8b69fbc7f7776550c993 (diff)
downloadx86-b654cc025fc36c9487d9f2aa33c23a99d43706c4.tar.gz
ring-buffer: Prevent overflow of size in ring_buffer_resize()
If the size passed to ring_buffer_resize() is greater than MAX_LONG - BUF_PAGE_SIZE then the DIV_ROUND_UP() will return zero. Here's the details: # echo 18014398509481980 > /sys/kernel/debug/tracing/buffer_size_kb tracing_entries_write() processes this and converts kb to bytes. 18014398509481980 << 10 = 18446744073709547520 and this is passed to ring_buffer_resize() as unsigned long size. size = DIV_ROUND_UP(size, BUF_PAGE_SIZE); Where DIV_ROUND_UP(a, b) is (a + b - 1)/b BUF_PAGE_SIZE is 4080 and here 18446744073709547520 + 4080 - 1 = 18446744073709551599 where 18446744073709551599 is still smaller than 2^64 2^64 - 18446744073709551599 = 17 But now 18446744073709551599 / 4080 = 4521260802379792 and size = size * 4080 = 18446744073709551360 This is checked to make sure its still greater than 2 * 4080, which it is. Then we convert to the number of buffer pages needed. nr_page = DIV_ROUND_UP(size, BUF_PAGE_SIZE) but this time size is 18446744073709551360 and 2^64 - (18446744073709551360 + 4080 - 1) = -3823 Thus it overflows and the resulting number is less than 4080, which makes 3823 / 4080 = 0 an nr_pages is set to this. As we already checked against the minimum that nr_pages may be, this causes the logic to fail as well, and we crash the kernel. There's no reason to have the two DIV_ROUND_UP() (that's just result of historical code changes), clean up the code and fix this bug. Change-Id: I6b0336dc15e5f9e789427bbf36c6d265352e408d Tracked-On: https://jira01.devtools.intel.com/browse/AW-3683 Cc: stable@vger.kernel.org # 3.5+ Fixes: 83f40318dab00 ("ring-buffer: Make removal of ring buffer pages atomic") Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Reviewed-on: https://android.intel.com/557934 Reviewed-by: Korpershoek, MattijsX <mattijsx.korpershoek@intel.com> Reviewed-by: Louis, FabienX <fabienx.louis@intel.com> Tested-by: Louis, FabienX <fabienx.louis@intel.com> Reviewed-by: Akue, LoicX <loicx.akue@intel.com> Reviewed-by: Maalem, Saadi <saadi.maalem@intel.com> (cherry picked from commit 8871d5a5bfde8b740b96cf9e6a1dcd394b433e58) Reviewed-on: https://android.intel.com/561359 Reviewed-by: Deverge, Jean-francoisX <jean-francoisx.deverge@intel.com>
-rw-r--r--kernel/trace/ring_buffer.c9
1 files changed, 4 insertions, 5 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index cb73c4e0741e..1f0676b1c83b 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -1643,14 +1643,13 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
!cpumask_test_cpu(cpu_id, buffer->cpumask))
return size;
- size = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
- size *= BUF_PAGE_SIZE;
+ nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
/* we need a minimum of two pages */
- if (size < BUF_PAGE_SIZE * 2)
- size = BUF_PAGE_SIZE * 2;
+ if (nr_pages < 2)
+ nr_pages = 2;
- nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
+ size = nr_pages * BUF_PAGE_SIZE;
/*
* Don't succeed if resizing is disabled, as a reader might be