mm: slub: Fix slab walking for init_on_free
To properly clear the slab on free with slab_want_init_on_free, we walk
the list of free objects using get_freepointer/set_freepointer.
The value we get from get_freepointer may not be valid. This isn't an
issue since an actual value will get written later but this means
there's a chance of triggering a bug if we use this value with
set_freepointer:
kernel BUG at mm/slub.c:306!
invalid opcode: 0000 [#1] PREEMPT PTI
CPU: 0 PID: 0 Comm: swapper Not tainted 5.2.0-05754-g6471384a #4
RIP: 0010:kfree+0x58a/0x5c0
Code: 48 83 05 78 37 51 02 01 0f 0b 48 83 05 7e 37 51 02 01 48 83 05 7e 37 51 02 01 48 83 05 7e 37 51 02 01 48 83 05 d6 37 51 02 01 <0f> 0b 48 83 05 d4 37 51 02 01 48 83 05 d4 37 51 02 01 48 83 05 d4
RSP: 0000:ffffffff82603d90 EFLAGS: 00010002
RAX: ffff8c3976c04320 RBX: ffff8c3976c04300 RCX: 0000000000000000
RDX: ffff8c3976c04300 RSI: 0000000000000000 RDI: ffff8c3976c04320
RBP: ffffffff82603db8 R08: 0000000000000000 R09: 0000000000000000
R10: ffff8c3976c04320 R11: ffffffff8289e1e0 R12: ffffd52cc8db0100
R13: ffff8c3976c01a00 R14: ffffffff810f10d4 R15: ffff8c3976c04300
FS: 0000000000000000(0000) GS:ffffffff8266b000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffff8c397ffff000 CR3: 0000000125020000 CR4: 00000000000406b0
Call Trace:
apply_wqattrs_prepare+0x154/0x280
apply_workqueue_attrs_locked+0x4e/0xe0
apply_workqueue_attrs+0x36/0x60
alloc_workqueue+0x25a/0x6d0
workqueue_init_early+0x246/0x348
start_kernel+0x3c7/0x7ec
x86_64_start_reservations+0x40/0x49
x86_64_start_kernel+0xda/0xe4
secondary_startup_64+0xb6/0xc0
Modules linked in:
---[ end trace f67eb9af4d8d492b ]---
Fix this by ensuring the value we set with set_freepointer is either NULL
or another value in the chain.
Reported-by: kernel test robot <rong.a.chen@intel.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
Fixes: 6471384af2
("mm: security: introduce init_on_alloc=1 and init_on_free=1 boot options")
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
d2eee9fca1
commit
1b7e816fc8
|
@ -1432,7 +1432,9 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
|
||||||
void *old_tail = *tail ? *tail : *head;
|
void *old_tail = *tail ? *tail : *head;
|
||||||
int rsize;
|
int rsize;
|
||||||
|
|
||||||
if (slab_want_init_on_free(s))
|
if (slab_want_init_on_free(s)) {
|
||||||
|
void *p = NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
object = next;
|
object = next;
|
||||||
next = get_freepointer(s, object);
|
next = get_freepointer(s, object);
|
||||||
|
@ -1445,8 +1447,10 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
|
||||||
: 0;
|
: 0;
|
||||||
memset((char *)object + s->inuse, 0,
|
memset((char *)object + s->inuse, 0,
|
||||||
s->size - s->inuse - rsize);
|
s->size - s->inuse - rsize);
|
||||||
set_freepointer(s, object, next);
|
set_freepointer(s, object, p);
|
||||||
|
p = object;
|
||||||
} while (object != old_tail);
|
} while (object != old_tail);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compiler cannot detect this function can be removed if slab_free_hook()
|
* Compiler cannot detect this function can be removed if slab_free_hook()
|
||||||
|
|
Loading…
Reference in a new issue