@@ -360,13 +360,19 @@ static struct workqueue_struct *flushwq;
360
360
* Core slab cache functions
361
361
*******************************************************************/
362
362
363
+ /*
364
+ * freeptr_t represents a SLUB freelist pointer, which might be encoded
365
+ * and not dereferenceable if CONFIG_SLAB_FREELIST_HARDENED is enabled.
366
+ */
367
+ typedef struct { unsigned long v ; } freeptr_t ;
368
+
363
369
/*
364
370
* Returns freelist pointer (ptr). With hardening, this is obfuscated
365
371
* with an XOR of the address where the pointer is held and a per-cache
366
372
* random number.
367
373
*/
368
- static inline void * freelist_ptr (const struct kmem_cache * s , void * ptr ,
369
- unsigned long ptr_addr )
374
+ static inline freeptr_t freelist_ptr_encode (const struct kmem_cache * s ,
375
+ void * ptr , unsigned long ptr_addr )
370
376
{
371
377
#ifdef CONFIG_SLAB_FREELIST_HARDENED
372
378
/*
@@ -379,25 +385,40 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr,
379
385
* calls get_freepointer() with an untagged pointer, which causes the
380
386
* freepointer to be restored incorrectly.
381
387
*/
382
- return (void * )( (unsigned long )ptr ^ s -> random ^
383
- swab ((unsigned long )kasan_reset_tag ((void * )ptr_addr ))) ;
388
+ return (freeptr_t ){. v = (unsigned long )ptr ^ s -> random ^
389
+ swab ((unsigned long )kasan_reset_tag ((void * )ptr_addr ))} ;
384
390
#else
385
- return ptr ;
391
+ return ( freeptr_t ){. v = ( unsigned long ) ptr } ;
386
392
#endif
387
393
}
388
394
395
+ static inline void * freelist_ptr_decode (const struct kmem_cache * s ,
396
+ freeptr_t ptr , unsigned long ptr_addr )
397
+ {
398
+ void * decoded ;
399
+
400
+ #ifdef CONFIG_SLAB_FREELIST_HARDENED
401
+ /* See the comment in freelist_ptr_encode */
402
+ decoded = (void * )(ptr .v ^ s -> random ^
403
+ swab ((unsigned long )kasan_reset_tag ((void * )ptr_addr )));
404
+ #else
405
+ decoded = (void * )ptr .v ;
406
+ #endif
407
+ return decoded ;
408
+ }
409
+
389
410
/* Returns the freelist pointer recorded at location ptr_addr. */
390
411
static inline void * freelist_dereference (const struct kmem_cache * s ,
391
412
void * ptr_addr )
392
413
{
393
- return freelist_ptr (s , ( void * ) * ( unsigned long * )(ptr_addr ),
414
+ return freelist_ptr_decode (s , * ( freeptr_t * )(ptr_addr ),
394
415
(unsigned long )ptr_addr );
395
416
}
396
417
397
418
static inline void * get_freepointer (struct kmem_cache * s , void * object )
398
419
{
399
420
object = kasan_reset_tag (object );
400
- return freelist_dereference (s , object + s -> offset );
421
+ return freelist_dereference (s , ( freeptr_t * )( object + s -> offset ) );
401
422
}
402
423
403
424
#ifndef CONFIG_SLUB_TINY
@@ -421,15 +442,15 @@ __no_kmsan_checks
421
442
static inline void * get_freepointer_safe (struct kmem_cache * s , void * object )
422
443
{
423
444
unsigned long freepointer_addr ;
424
- void * p ;
445
+ freeptr_t p ;
425
446
426
447
if (!debug_pagealloc_enabled_static ())
427
448
return get_freepointer (s , object );
428
449
429
450
object = kasan_reset_tag (object );
430
451
freepointer_addr = (unsigned long )object + s -> offset ;
431
- copy_from_kernel_nofault (& p , (void * * )freepointer_addr , sizeof (p ));
432
- return freelist_ptr (s , p , freepointer_addr );
452
+ copy_from_kernel_nofault (& p , (freeptr_t * )freepointer_addr , sizeof (p ));
453
+ return freelist_ptr_decode (s , p , freepointer_addr );
433
454
}
434
455
435
456
static inline void set_freepointer (struct kmem_cache * s , void * object , void * fp )
@@ -441,7 +462,7 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
441
462
#endif
442
463
443
464
freeptr_addr = (unsigned long )kasan_reset_tag ((void * )freeptr_addr );
444
- * (void * * )freeptr_addr = freelist_ptr (s , fp , freeptr_addr );
465
+ * (freeptr_t * )freeptr_addr = freelist_ptr_encode (s , fp , freeptr_addr );
445
466
}
446
467
447
468
/* Loop over all objects in a slab */
0 commit comments