mirror of
https://github.com/S3NEO/android_kernel_samsung_msm8226.git
synced 2024-11-07 03:47:13 +00:00
UPSTREAM: ring-buffer: Prevent overflow of size in ring_buffer_resize()
(Cherry picked from commit 59643d1535eb220668692a5359de22545af579f6) 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. 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> Signed-off-by: Willy Tarreau <w@1wt.eu> Change-Id: I1147672317a3ad0fc995b1f32baaa050a7976ac4 Bug: 32659848 CVE-2016-9754 Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org>
This commit is contained in:
parent
e212bc1d16
commit
68ad8d0dea
1 changed files with 5 additions and 6 deletions
|
@ -1300,13 +1300,14 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
size = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
|
nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
|
||||||
size *= BUF_PAGE_SIZE;
|
|
||||||
buffer_size = buffer->pages * BUF_PAGE_SIZE;
|
buffer_size = buffer->pages * BUF_PAGE_SIZE;
|
||||||
|
|
||||||
/* we need a minimum of two pages */
|
/* we need a minimum of two pages */
|
||||||
if (size < BUF_PAGE_SIZE * 2)
|
if (nr_pages < 2)
|
||||||
size = BUF_PAGE_SIZE * 2;
|
nr_pages = 2;
|
||||||
|
|
||||||
|
size = nr_pages * BUF_PAGE_SIZE;
|
||||||
|
|
||||||
if (size == buffer_size)
|
if (size == buffer_size)
|
||||||
return size;
|
return size;
|
||||||
|
@ -1319,8 +1320,6 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
|
||||||
mutex_lock(&buffer->mutex);
|
mutex_lock(&buffer->mutex);
|
||||||
get_online_cpus();
|
get_online_cpus();
|
||||||
|
|
||||||
nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
|
|
||||||
|
|
||||||
if (size < buffer_size) {
|
if (size < buffer_size) {
|
||||||
|
|
||||||
/* easy case, just free pages */
|
/* easy case, just free pages */
|
||||||
|
|
Loading…
Reference in a new issue