If ksize() is used on an allocation, the compiler cannot make any assumptions about its size any more (as hinted by __alloc_size). Force it to forget. One caller was using a container_of() construction that needed to be worked around. Cc: Marco Elver <elver@xxxxxxxxxx> Cc: Pekka Enberg <penberg@xxxxxxxxxx> Cc: David Rientjes <rientjes@xxxxxxxxxx> Cc: Joonsoo Kim <iamjoonsoo.kim@xxxxxxx> Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> Cc: Vlastimil Babka <vbabka@xxxxxxx> Cc: linux-mm@xxxxxxxxx Link: https://github.com/ClangBuiltLinux/linux/issues/1599 Fixes: c37495d6254c ("slab: add __alloc_size attributes for better bounds checking") Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx> --- This appears to work for me, but I'm waiting for more feedback on the specific instance got tripped over in Android. --- drivers/base/devres.c | 4 +++- include/linux/slab.h | 26 +++++++++++++++++++++++++- mm/slab_common.c | 19 +++---------------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index eaa9a5cd1db9..1a2645bd7234 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -855,6 +855,7 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) size_t total_new_size, total_old_size; struct devres *old_dr, *new_dr; unsigned long flags; + void *allocation; if (unlikely(!new_size)) { devm_kfree(dev, ptr); @@ -874,7 +875,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) if (!check_dr_size(new_size, &total_new_size)) return NULL; - total_old_size = ksize(container_of(ptr, struct devres, data)); + allocation = container_of(ptr, struct devres, data); + total_old_size = ksize(allocation); if (total_old_size == 0) { WARN(1, "Pointer doesn't point to dynamically allocated memory."); return NULL; diff --git a/include/linux/slab.h b/include/linux/slab.h index 37bde99b74af..a14f3bfa2f44 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -182,8 +182,32 @@ int kmem_cache_shrink(struct kmem_cache *s); void * __must_check krealloc(const void *objp, size_t new_size, gfp_t flags) __alloc_size(2); void kfree(const void *objp); void kfree_sensitive(const void *objp); + +/** + * ksize - get the actual amount of memory allocated for a given object + * @objp: Pointer to the object + * + * kmalloc may internally round up allocations and return more memory + * than requested. ksize() can be used to determine the actual amount of + * memory allocated. The caller may use this additional memory, even though + * a smaller amount of memory was initially specified with the kmalloc call. + * The caller must guarantee that objp points to a valid object previously + * allocated with either kmalloc() or kmem_cache_alloc(). The object + * must not be freed during the duration of the call. + * + * Return: size of the actual memory used by @objp in bytes + */ +#define ksize(objp) ({ \ + /* \ + * Getting the actual allocation size means the __alloc_size \ + * hints are no longer valid, and the compiler needs to \ + * forget about them. \ + */ \ + OPTIMIZER_HIDE_VAR(objp); \ + _ksize(objp); \ +}) size_t __ksize(const void *objp); -size_t ksize(const void *objp); +size_t _ksize(const void *objp); #ifdef CONFIG_PRINTK bool kmem_valid_obj(void *object); void kmem_dump_obj(void *object); diff --git a/mm/slab_common.c b/mm/slab_common.c index 23f2ab0713b7..ba5fa8481396 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -1245,21 +1245,8 @@ void kfree_sensitive(const void *p) } EXPORT_SYMBOL(kfree_sensitive); -/** - * ksize - get the actual amount of memory allocated for a given object - * @objp: Pointer to the object - * - * kmalloc may internally round up allocations and return more memory - * than requested. ksize() can be used to determine the actual amount of - * memory allocated. The caller may use this additional memory, even though - * a smaller amount of memory was initially specified with the kmalloc call. - * The caller must guarantee that objp points to a valid object previously - * allocated with either kmalloc() or kmem_cache_alloc(). The object - * must not be freed during the duration of the call. - * - * Return: size of the actual memory used by @objp in bytes - */ -size_t ksize(const void *objp) +/* Should not be called directly: use "ksize" macro wrapper. */ +size_t _ksize(const void *objp) { size_t size; @@ -1289,7 +1276,7 @@ size_t ksize(const void *objp) kasan_unpoison_range(objp, size); return size; } -EXPORT_SYMBOL(ksize); +EXPORT_SYMBOL(_ksize); /* Tracepoints definitions. */ EXPORT_TRACEPOINT_SYMBOL(kmalloc); -- 2.30.2