mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-03 17:40:04 +00:00
![Kees Cook](/assets/img/avatar_default.png)
The early malloc() and free() implementation in include/linux/decompress/mm.h (which is also included by the static decompressors) is static. This is fine when the only thing interested in using malloc() is the decompression code, but the x86 early boot environment may use malloc() in a couple places, leading to a potential collision when the static copies of the available memory region ("malloc_ptr") gets reset to the global "free_mem_ptr" value. As it happened, the existing usage pattern was accidentally safe because each user did 1 malloc() and 1 free() before returning and were not nested: extract_kernel() (misc.c) choose_random_location() (kaslr.c) mem_avoid_init() handle_mem_options() malloc() ... free() ... parse_elf() (misc.c) malloc() ... free() Once the future FGKASLR series is added, however, it will insert additional malloc() calls local to fgkaslr.c in the middle of parse_elf()'s malloc()/free() pair: parse_elf() (misc.c) malloc() if (...) { layout_randomized_image(output, &ehdr, phdrs); malloc() <- boom ... else layout_image(output, &ehdr, phdrs); free() To avoid collisions, there must be a single implementation of malloc(). Adjust include/linux/decompress/mm.h so that visibility can be controlled, provide prototypes in misc.h, and implement the functions in misc.c. This also results in a small size savings: $ size vmlinux.before vmlinux.after text data bss dec hex filename 8842314 468 178320 9021102 89a6ae vmlinux.before 8842240 468 178320 9021028 89a664 vmlinux.after Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20211013175742.1197608-4-keescook@chromium.org
102 lines
2.1 KiB
C
102 lines
2.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* linux/compr_mm.h
|
|
*
|
|
* Memory management for pre-boot and ramdisk uncompressors
|
|
*
|
|
* Authors: Alain Knaff <alain@knaff.lu>
|
|
*
|
|
*/
|
|
|
|
#ifndef DECOMPR_MM_H
|
|
#define DECOMPR_MM_H
|
|
|
|
#ifdef STATIC
|
|
|
|
/* Code active when included from pre-boot environment: */
|
|
|
|
/*
|
|
* Some architectures want to ensure there is no local data in their
|
|
* pre-boot environment, so that data can arbitrarily relocated (via
|
|
* GOT references). This is achieved by defining STATIC_RW_DATA to
|
|
* be null.
|
|
*/
|
|
#ifndef STATIC_RW_DATA
|
|
#define STATIC_RW_DATA static
|
|
#endif
|
|
|
|
/*
|
|
* When an architecture needs to share the malloc()/free() implementation
|
|
* between compilation units, it needs to have non-local visibility.
|
|
*/
|
|
#ifndef MALLOC_VISIBLE
|
|
#define MALLOC_VISIBLE static
|
|
#endif
|
|
|
|
/* A trivial malloc implementation, adapted from
|
|
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
|
|
*/
|
|
STATIC_RW_DATA unsigned long malloc_ptr;
|
|
STATIC_RW_DATA int malloc_count;
|
|
|
|
MALLOC_VISIBLE void *malloc(int size)
|
|
{
|
|
void *p;
|
|
|
|
if (size < 0)
|
|
return NULL;
|
|
if (!malloc_ptr)
|
|
malloc_ptr = free_mem_ptr;
|
|
|
|
malloc_ptr = (malloc_ptr + 3) & ~3; /* Align */
|
|
|
|
p = (void *)malloc_ptr;
|
|
malloc_ptr += size;
|
|
|
|
if (free_mem_end_ptr && malloc_ptr >= free_mem_end_ptr)
|
|
return NULL;
|
|
|
|
malloc_count++;
|
|
return p;
|
|
}
|
|
|
|
MALLOC_VISIBLE void free(void *where)
|
|
{
|
|
malloc_count--;
|
|
if (!malloc_count)
|
|
malloc_ptr = free_mem_ptr;
|
|
}
|
|
|
|
#define large_malloc(a) malloc(a)
|
|
#define large_free(a) free(a)
|
|
|
|
#define INIT
|
|
|
|
#else /* STATIC */
|
|
|
|
/* Code active when compiled standalone for use when loading ramdisk: */
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/string.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
/* Use defines rather than static inline in order to avoid spurious
|
|
* warnings when not needed (indeed large_malloc / large_free are not
|
|
* needed by inflate */
|
|
|
|
#define malloc(a) kmalloc(a, GFP_KERNEL)
|
|
#define free(a) kfree(a)
|
|
|
|
#define large_malloc(a) vmalloc(a)
|
|
#define large_free(a) vfree(a)
|
|
|
|
#define INIT __init
|
|
#define STATIC
|
|
|
|
#include <linux/init.h>
|
|
|
|
#endif /* STATIC */
|
|
|
|
#endif /* DECOMPR_MM_H */
|