slab fixes for 6.9-rc7
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEe7vIQRWZI0iWSE3xu+CwddJFiJoFAmY4pYcACgkQu+CwddJF iJpdxAf/eRUaRSJ2mI2XbK8yzvzCmWMU7xh5uMTCfXIKzvf5sBV5xXRLKi+owJ+k artBjIHzZ7Y0DFS3dJboY1iyjpTMzC8Mn1kWUNV+7N44FaOaICckBgi7q2iyayQG O/aukwwCh4dDpQqY0LeLg39UicLU4uS/8NDkII6CJQTep6tpbtvLGxONwlkbd9x2 9EDPC1Y3p2M0N7P12pJs/nwRx7vxdHTmBcE72OU6wq7sWLou2vzSVBzWlFfnEURD Kbq3/7y6WRhSmz05WCJ+BGEMSvwjM9YMn56LfHDa/mGCySH2/Wr/d39hVTv746zG 66anLCU/NpqtzTn5wM3vunKRh+K3Eg== =+O33 -----END PGP SIGNATURE----- Merge tag 'slab-for-6.9-rc7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab Pull slab fixes from Vlastimil Babka: - Fix for cleanup infrastructure (Dan Carpenter) This makes the __free(kfree) cleanup hooks not crash on error pointers. - SLUB fix for freepointer checking (Nicolas Bouchinet) This fixes a recently introduced bug that manifests when init_on_free, CONFIG_SLAB_FREELIST_HARDENED and consistency checks (slub_debug=F) are all enabled, and results in false-positive freepointer corrupt reports for caches that store freepointer outside of the object area. * tag 'slab-for-6.9-rc7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab: mm/slab: make __free(kfree) accept error pointers mm/slub: avoid zeroing outside-object freepointer for single free
This commit is contained in:
commit
ee5b455b0a
@ -266,7 +266,7 @@ void kfree(const void *objp);
|
||||
void kfree_sensitive(const void *objp);
|
||||
size_t __ksize(const void *objp);
|
||||
|
||||
DEFINE_FREE(kfree, void *, if (_T) kfree(_T))
|
||||
DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))
|
||||
|
||||
/**
|
||||
* ksize - Report actual allocation size of associated object
|
||||
@ -792,7 +792,7 @@ static inline __alloc_size(1, 2) void *kvcalloc(size_t n, size_t size, gfp_t fla
|
||||
extern void *kvrealloc(const void *p, size_t oldsize, size_t newsize, gfp_t flags)
|
||||
__realloc_size(3);
|
||||
extern void kvfree(const void *addr);
|
||||
DEFINE_FREE(kvfree, void *, if (_T) kvfree(_T))
|
||||
DEFINE_FREE(kvfree, void *, if (!IS_ERR_OR_NULL(_T)) kvfree(_T))
|
||||
|
||||
extern void kvfree_sensitive(const void *addr, size_t len);
|
||||
|
||||
|
52
mm/slub.c
52
mm/slub.c
@ -557,6 +557,26 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
|
||||
*(freeptr_t *)freeptr_addr = freelist_ptr_encode(s, fp, freeptr_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* See comment in calculate_sizes().
|
||||
*/
|
||||
static inline bool freeptr_outside_object(struct kmem_cache *s)
|
||||
{
|
||||
return s->offset >= s->inuse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return offset of the end of info block which is inuse + free pointer if
|
||||
* not overlapping with object.
|
||||
*/
|
||||
static inline unsigned int get_info_end(struct kmem_cache *s)
|
||||
{
|
||||
if (freeptr_outside_object(s))
|
||||
return s->inuse + sizeof(void *);
|
||||
else
|
||||
return s->inuse;
|
||||
}
|
||||
|
||||
/* Loop over all objects in a slab */
|
||||
#define for_each_object(__p, __s, __addr, __objects) \
|
||||
for (__p = fixup_red_left(__s, __addr); \
|
||||
@ -845,26 +865,6 @@ static void print_section(char *level, char *text, u8 *addr,
|
||||
metadata_access_disable();
|
||||
}
|
||||
|
||||
/*
|
||||
* See comment in calculate_sizes().
|
||||
*/
|
||||
static inline bool freeptr_outside_object(struct kmem_cache *s)
|
||||
{
|
||||
return s->offset >= s->inuse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return offset of the end of info block which is inuse + free pointer if
|
||||
* not overlapping with object.
|
||||
*/
|
||||
static inline unsigned int get_info_end(struct kmem_cache *s)
|
||||
{
|
||||
if (freeptr_outside_object(s))
|
||||
return s->inuse + sizeof(void *);
|
||||
else
|
||||
return s->inuse;
|
||||
}
|
||||
|
||||
static struct track *get_track(struct kmem_cache *s, void *object,
|
||||
enum track_item alloc)
|
||||
{
|
||||
@ -2092,15 +2092,20 @@ bool slab_free_hook(struct kmem_cache *s, void *x, bool init)
|
||||
*
|
||||
* The initialization memset's clear the object and the metadata,
|
||||
* but don't touch the SLAB redzone.
|
||||
*
|
||||
* The object's freepointer is also avoided if stored outside the
|
||||
* object.
|
||||
*/
|
||||
if (unlikely(init)) {
|
||||
int rsize;
|
||||
unsigned int inuse;
|
||||
|
||||
inuse = get_info_end(s);
|
||||
if (!kasan_has_integrated_init())
|
||||
memset(kasan_reset_tag(x), 0, s->object_size);
|
||||
rsize = (s->flags & SLAB_RED_ZONE) ? s->red_left_pad : 0;
|
||||
memset((char *)kasan_reset_tag(x) + s->inuse, 0,
|
||||
s->size - s->inuse - rsize);
|
||||
memset((char *)kasan_reset_tag(x) + inuse, 0,
|
||||
s->size - inuse - rsize);
|
||||
}
|
||||
/* KASAN might put x into memory quarantine, delaying its reuse. */
|
||||
return !kasan_slab_free(s, x, init);
|
||||
@ -3722,7 +3727,8 @@ static void *__slab_alloc_node(struct kmem_cache *s,
|
||||
static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
|
||||
void *obj)
|
||||
{
|
||||
if (unlikely(slab_want_init_on_free(s)) && obj)
|
||||
if (unlikely(slab_want_init_on_free(s)) && obj &&
|
||||
!freeptr_outside_object(s))
|
||||
memset((void *)((char *)kasan_reset_tag(obj) + s->offset),
|
||||
0, sizeof(void *));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user