Skip to content

Commit d8f117a

Browse files
UladzislauRezkitorvalds
authored andcommitted
z3fold: fix use-after-free when freeing handles
free_handle() for a foreign handle may race with inter-page compaction, what can lead to memory corruption. To avoid that, take write lock not read lock in free_handle to be synchronized with __release_z3fold_page(). For example KASAN can detect it: ================================================================== BUG: KASAN: use-after-free in LZ4_decompress_safe+0x2c4/0x3b8 Read of size 1 at addr ffffffc976695ca3 by task GoogleApiHandle/4121 CPU: 0 PID: 4121 Comm: GoogleApiHandle Tainted: P S OE 4.19.81-perf+ #162 Hardware name: Sony Mobile Communications. PDX-203(KONA) (DT) Call trace: LZ4_decompress_safe+0x2c4/0x3b8 lz4_decompress_crypto+0x3c/0x70 crypto_decompress+0x58/0x70 zcomp_decompress+0xd4/0x120 ... Apart from that, initialize zhdr->mapped_count in init_z3fold_page() and remove "newpage" variable because it is not used anywhere. Signed-off-by: Uladzislau Rezki <[email protected]> Signed-off-by: Vitaly Wool <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Cc: Qian Cai <[email protected]> Cc: Raymond Jennings <[email protected]> Cc: <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent c2bc26f commit d8f117a

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

mm/z3fold.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,16 +318,16 @@ static inline void free_handle(unsigned long handle)
318318
slots = handle_to_slots(handle);
319319
write_lock(&slots->lock);
320320
*(unsigned long *)handle = 0;
321-
write_unlock(&slots->lock);
322-
if (zhdr->slots == slots)
321+
if (zhdr->slots == slots) {
322+
write_unlock(&slots->lock);
323323
return; /* simple case, nothing else to do */
324+
}
324325

325326
/* we are freeing a foreign handle if we are here */
326327
zhdr->foreign_handles--;
327328
is_free = true;
328-
read_lock(&slots->lock);
329329
if (!test_bit(HANDLES_ORPHANED, &slots->pool)) {
330-
read_unlock(&slots->lock);
330+
write_unlock(&slots->lock);
331331
return;
332332
}
333333
for (i = 0; i <= BUDDY_MASK; i++) {
@@ -336,7 +336,7 @@ static inline void free_handle(unsigned long handle)
336336
break;
337337
}
338338
}
339-
read_unlock(&slots->lock);
339+
write_unlock(&slots->lock);
340340

341341
if (is_free) {
342342
struct z3fold_pool *pool = slots_to_pool(slots);
@@ -422,6 +422,7 @@ static struct z3fold_header *init_z3fold_page(struct page *page, bool headless,
422422
zhdr->start_middle = 0;
423423
zhdr->cpu = -1;
424424
zhdr->foreign_handles = 0;
425+
zhdr->mapped_count = 0;
425426
zhdr->slots = slots;
426427
zhdr->pool = pool;
427428
INIT_LIST_HEAD(&zhdr->buddy);

0 commit comments

Comments
 (0)