Skip to content

Commit 747e2cf

Browse files
Lilith Gkinitehcaster
authored andcommitted
slub: Handle freelist cycle in on_freelist()
The on_freelist() doesn't have a way to handle the edgecase of having a full freelist that doesn't end in NULL and instead has another valid pointer in the slab as a result of a Use-After-Free or anything similar. This case won't get caught by check_valid_pointer() and it will result in nr incrementing to `slab->objects + 1`, corrupting the slab->inuse entry later in the code by setting it to -1. Add an if check to detect that case, report it and handle the freelist and slab appropriately, as is the standard process in these situations. Furthermore change the return type of the function from int to bool as per coding style guidelines. Also move the `break;` line inside the `if (object) {` to make it more obvious that the code breaks the while loop in that branch. Signed-off-by: Lilith Persefoni Gkini <[email protected]> Reviewed-by: Harry Yoo <[email protected]> Signed-off-by: Vlastimil Babka <[email protected]>
1 parent 939c5de commit 747e2cf

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

mm/slub.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ static int check_slab(struct kmem_cache *s, struct slab *slab)
14411441
* Determine if a certain object in a slab is on the freelist. Must hold the
14421442
* slab lock to guarantee that the chains are in a consistent state.
14431443
*/
1444-
static int on_freelist(struct kmem_cache *s, struct slab *slab, void *search)
1444+
static bool on_freelist(struct kmem_cache *s, struct slab *slab, void *search)
14451445
{
14461446
int nr = 0;
14471447
void *fp;
@@ -1451,26 +1451,34 @@ static int on_freelist(struct kmem_cache *s, struct slab *slab, void *search)
14511451
fp = slab->freelist;
14521452
while (fp && nr <= slab->objects) {
14531453
if (fp == search)
1454-
return 1;
1454+
return true;
14551455
if (!check_valid_pointer(s, slab, fp)) {
14561456
if (object) {
14571457
object_err(s, slab, object,
14581458
"Freechain corrupt");
14591459
set_freepointer(s, object, NULL);
1460+
break;
14601461
} else {
14611462
slab_err(s, slab, "Freepointer corrupt");
14621463
slab->freelist = NULL;
14631464
slab->inuse = slab->objects;
14641465
slab_fix(s, "Freelist cleared");
1465-
return 0;
1466+
return false;
14661467
}
1467-
break;
14681468
}
14691469
object = fp;
14701470
fp = get_freepointer(s, object);
14711471
nr++;
14721472
}
14731473

1474+
if (nr > slab->objects) {
1475+
slab_err(s, slab, "Freelist cycle detected");
1476+
slab->freelist = NULL;
1477+
slab->inuse = slab->objects;
1478+
slab_fix(s, "Freelist cleared");
1479+
return false;
1480+
}
1481+
14741482
max_objects = order_objects(slab_order(slab), s->size);
14751483
if (max_objects > MAX_OBJS_PER_PAGE)
14761484
max_objects = MAX_OBJS_PER_PAGE;

0 commit comments

Comments
 (0)