summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2022-2959.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2022-2959.patch')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2022-2959.patch97
1 files changed, 97 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2022-2959.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2022-2959.patch
new file mode 100644
index 000000000..f8117d0a7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2022-2959.patch
@@ -0,0 +1,97 @@
+From 189b0ddc245139af81198d1a3637cac74f96e13a Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 26 May 2022 07:34:52 +0100
+Subject: [PATCH] pipe: Fix missing lock in pipe_resize_ring()
+
+pipe_resize_ring() needs to take the pipe->rd_wait.lock spinlock to
+prevent post_one_notification() from trying to insert into the ring
+whilst the ring is being replaced.
+
+The occupancy check must be done after the lock is taken, and the lock
+must be taken after the new ring is allocated.
+
+The bug can lead to an oops looking something like:
+
+ BUG: KASAN: use-after-free in post_one_notification.isra.0+0x62e/0x840
+ Read of size 4 at addr ffff88801cc72a70 by task poc/27196
+ ...
+ Call Trace:
+ post_one_notification.isra.0+0x62e/0x840
+ __post_watch_notification+0x3b7/0x650
+ key_create_or_update+0xb8b/0xd20
+ __do_sys_add_key+0x175/0x340
+ __x64_sys_add_key+0xbe/0x140
+ do_syscall_64+0x5c/0xc0
+ entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+Reported by Selim Enes Karaduman @Enesdex working with Trend Micro Zero
+Day Initiative.
+
+Fixes: c73be61cede5 ("pipe: Add general notification queue support")
+Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-17291
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ fs/pipe.c | 31 ++++++++++++++++++-------------
+ 1 file changed, 18 insertions(+), 13 deletions(-)
+
+diff --git a/fs/pipe.c b/fs/pipe.c
+index e140ea150bbb14..11358569a7779a 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -1245,30 +1245,33 @@ unsigned int round_pipe_size(unsigned long size)
+
+ /*
+ * Resize the pipe ring to a number of slots.
++ *
++ * Note the pipe can be reduced in capacity, but only if the current
++ * occupancy doesn't exceed nr_slots; if it does, EBUSY will be
++ * returned instead.
+ */
+ int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots)
+ {
+ struct pipe_buffer *bufs;
+ unsigned int head, tail, mask, n;
+
+- /*
+- * We can shrink the pipe, if arg is greater than the ring occupancy.
+- * Since we don't expect a lot of shrink+grow operations, just free and
+- * allocate again like we would do for growing. If the pipe currently
+- * contains more buffers than arg, then return busy.
+- */
+- mask = pipe->ring_size - 1;
+- head = pipe->head;
+- tail = pipe->tail;
+- n = pipe_occupancy(pipe->head, pipe->tail);
+- if (nr_slots < n)
+- return -EBUSY;
+-
+ bufs = kcalloc(nr_slots, sizeof(*bufs),
+ GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
+ if (unlikely(!bufs))
+ return -ENOMEM;
+
++ spin_lock_irq(&pipe->rd_wait.lock);
++ mask = pipe->ring_size - 1;
++ head = pipe->head;
++ tail = pipe->tail;
++
++ n = pipe_occupancy(head, tail);
++ if (nr_slots < n) {
++ spin_unlock_irq(&pipe->rd_wait.lock);
++ kfree(bufs);
++ return -EBUSY;
++ }
++
+ /*
+ * The pipe array wraps around, so just start the new one at zero
+ * and adjust the indices.
+@@ -1300,6 +1303,8 @@ int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots)
+ pipe->tail = tail;
+ pipe->head = head;
+
++ spin_unlock_irq(&pipe->rd_wait.lock);
++
+ /* This might have made more room for writers */
+ wake_up_interruptible(&pipe->wr_wait);
+ return 0;