Commit 82138f01 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull slab fix from Vlastimil Babka:

 - A stable fix for k(v)ealloc() where reallocating on a different node
   or shrinking the object can result in either losing the original data
   or a buffer overflow (Marco Elver)

* tag 'slab-for-7.1-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab:
  slub: fix data loss and overflow in krealloc()
parents bbc4af7a 082a6d03
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -6645,16 +6645,6 @@ __do_krealloc(const void *p, size_t new_size, unsigned long align, gfp_t flags,
	if (!kasan_check_byte(p))
		return NULL;

	/*
	 * If reallocation is not necessary (e. g. the new size is less
	 * than the current allocated size), the current allocation will be
	 * preserved unless __GFP_THISNODE is set. In the latter case a new
	 * allocation on the requested node will be attempted.
	 */
	if (unlikely(flags & __GFP_THISNODE) && nid != NUMA_NO_NODE &&
		     nid != page_to_nid(virt_to_page(p)))
		goto alloc_new;

	if (is_kfence_address(p)) {
		ks = orig_size = kfence_ksize(p);
	} else {
@@ -6673,6 +6663,16 @@ __do_krealloc(const void *p, size_t new_size, unsigned long align, gfp_t flags,
		}
	}

	/*
	 * If reallocation is not necessary (e. g. the new size is less
	 * than the current allocated size), the current allocation will be
	 * preserved unless __GFP_THISNODE is set. In the latter case a new
	 * allocation on the requested node will be attempted.
	 */
	if (unlikely(flags & __GFP_THISNODE) && nid != NUMA_NO_NODE &&
		     nid != page_to_nid(virt_to_page(p)))
		goto alloc_new;

	/* If the old object doesn't fit, allocate a bigger one */
	if (new_size > ks)
		goto alloc_new;
@@ -6707,7 +6707,7 @@ __do_krealloc(const void *p, size_t new_size, unsigned long align, gfp_t flags,
	if (ret && p) {
		/* Disable KASAN checks as the object's redzone is accessed. */
		kasan_disable_current();
		memcpy(ret, kasan_reset_tag(p), orig_size ?: ks);
		memcpy(ret, kasan_reset_tag(p), min(new_size, (size_t)(orig_size ?: ks)));
		kasan_enable_current();
	}

@@ -6941,7 +6941,7 @@ void *kvrealloc_node_align_noprof(const void *p, size_t size, unsigned long alig
		if (p) {
			/* We already know that `p` is not a vmalloc address. */
			kasan_disable_current();
			memcpy(n, kasan_reset_tag(p), ksize(p));
			memcpy(n, kasan_reset_tag(p), min(size, ksize(p)));
			kasan_enable_current();

			kfree(p);