Skip to content

Commit 189b0dd

Browse files
dhowellstorvalds
authored andcommitted
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: c73be61 ("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>
1 parent 7e28407 commit 189b0dd

1 file changed

Lines changed: 18 additions & 13 deletions

File tree

fs/pipe.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,30 +1245,33 @@ unsigned int round_pipe_size(unsigned long size)
12451245

12461246
/*
12471247
* Resize the pipe ring to a number of slots.
1248+
*
1249+
* Note the pipe can be reduced in capacity, but only if the current
1250+
* occupancy doesn't exceed nr_slots; if it does, EBUSY will be
1251+
* returned instead.
12481252
*/
12491253
int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots)
12501254
{
12511255
struct pipe_buffer *bufs;
12521256
unsigned int head, tail, mask, n;
12531257

1254-
/*
1255-
* We can shrink the pipe, if arg is greater than the ring occupancy.
1256-
* Since we don't expect a lot of shrink+grow operations, just free and
1257-
* allocate again like we would do for growing. If the pipe currently
1258-
* contains more buffers than arg, then return busy.
1259-
*/
1260-
mask = pipe->ring_size - 1;
1261-
head = pipe->head;
1262-
tail = pipe->tail;
1263-
n = pipe_occupancy(pipe->head, pipe->tail);
1264-
if (nr_slots < n)
1265-
return -EBUSY;
1266-
12671258
bufs = kcalloc(nr_slots, sizeof(*bufs),
12681259
GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
12691260
if (unlikely(!bufs))
12701261
return -ENOMEM;
12711262

1263+
spin_lock_irq(&pipe->rd_wait.lock);
1264+
mask = pipe->ring_size - 1;
1265+
head = pipe->head;
1266+
tail = pipe->tail;
1267+
1268+
n = pipe_occupancy(head, tail);
1269+
if (nr_slots < n) {
1270+
spin_unlock_irq(&pipe->rd_wait.lock);
1271+
kfree(bufs);
1272+
return -EBUSY;
1273+
}
1274+
12721275
/*
12731276
* The pipe array wraps around, so just start the new one at zero
12741277
* and adjust the indices.
@@ -1300,6 +1303,8 @@ int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots)
13001303
pipe->tail = tail;
13011304
pipe->head = head;
13021305

1306+
spin_unlock_irq(&pipe->rd_wait.lock);
1307+
13031308
/* This might have made more room for writers */
13041309
wake_up_interruptible(&pipe->wr_wait);
13051310
return 0;

0 commit comments

Comments
 (0)