Commit 33f98a97 authored by Kees Cook's avatar Kees Cook Committed by Peter Zijlstra

x86/boot/compressed: Avoid duplicate malloc() implementations

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: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20211013175742.1197608-4-keescook@chromium.org
parent 0d054d4e
......@@ -32,10 +32,6 @@
#include <generated/utsrelease.h>
#include <asm/efi.h>
/* Macros used by the included decompressor code below. */
#define STATIC
#include <linux/decompress/mm.h>
#define _SETUP
#include <asm/setup.h> /* For COMMAND_LINE_SIZE */
#undef _SETUP
......
......@@ -28,6 +28,9 @@
/* Macros used by the included decompressor code below. */
#define STATIC static
/* Define an externally visible malloc()/free(). */
#define MALLOC_VISIBLE
#include <linux/decompress/mm.h>
/*
* Provide definitions of memzero and memmove as some of the decompressors will
......
......@@ -44,6 +44,8 @@ extern char _head[], _end[];
/* misc.c */
extern memptr free_mem_ptr;
extern memptr free_mem_end_ptr;
void *malloc(int size);
void free(void *where);
extern struct boot_params *boot_params;
void __putstr(const char *s);
void __puthex(unsigned long value);
......
......@@ -25,13 +25,21 @@
#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;
static void *malloc(int size)
MALLOC_VISIBLE void *malloc(int size)
{
void *p;
......@@ -52,7 +60,7 @@ static void *malloc(int size)
return p;
}
static void free(void *where)
MALLOC_VISIBLE void free(void *where)
{
malloc_count--;
if (!malloc_count)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment