Skip to content

Commit d6d1e3e

Browse files
Peter Zijlstrahansendc
authored andcommitted
mm/execmem: Unify early execmem_cache behaviour
Early kernel memory is RWX, only at the end of early boot (before SMP) do we mark things ROX. Have execmem_cache mirror this behaviour for early users. This avoids having to remember what code is execmem and what is not -- we can poke everything with impunity ;-) Also performance for not having to do endless text_poke_mm switches. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Pawan Gupta <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Alexandre Chartre <[email protected]>
1 parent f0cd709 commit d6d1e3e

File tree

4 files changed

+50
-4
lines changed

4 files changed

+50
-4
lines changed

arch/x86/mm/init_32.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/initrd.h>
3131
#include <linux/cpumask.h>
3232
#include <linux/gfp.h>
33+
#include <linux/execmem.h>
3334

3435
#include <asm/asm.h>
3536
#include <asm/bios_ebda.h>
@@ -755,6 +756,8 @@ void mark_rodata_ro(void)
755756
pr_info("Write protecting kernel text and read-only data: %luk\n",
756757
size >> 10);
757758

759+
execmem_cache_make_ro();
760+
758761
kernel_set_to_readonly = 1;
759762

760763
#ifdef CONFIG_CPA_DEBUG

arch/x86/mm/init_64.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <linux/gfp.h>
3535
#include <linux/kcore.h>
3636
#include <linux/bootmem_info.h>
37+
#include <linux/execmem.h>
3738

3839
#include <asm/processor.h>
3940
#include <asm/bios_ebda.h>
@@ -1391,6 +1392,8 @@ void mark_rodata_ro(void)
13911392
(end - start) >> 10);
13921393
set_memory_ro(start, (end - start) >> PAGE_SHIFT);
13931394

1395+
execmem_cache_make_ro();
1396+
13941397
kernel_set_to_readonly = 1;
13951398

13961399
/*

include/linux/execmem.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ enum execmem_range_flags {
5353
EXECMEM_ROX_CACHE = (1 << 1),
5454
};
5555

56-
#ifdef CONFIG_ARCH_HAS_EXECMEM_ROX
56+
#if defined(CONFIG_ARCH_HAS_EXECMEM_ROX) && defined(CONFIG_EXECMEM)
5757
/**
5858
* execmem_fill_trapping_insns - set memory to contain instructions that
5959
* will trap
@@ -93,9 +93,15 @@ int execmem_make_temp_rw(void *ptr, size_t size);
9393
* Return: 0 on success or negative error code on failure.
9494
*/
9595
int execmem_restore_rox(void *ptr, size_t size);
96+
97+
/*
98+
* Called from mark_readonly(), where the system transitions to ROX.
99+
*/
100+
void execmem_cache_make_ro(void);
96101
#else
97102
static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; }
98103
static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; }
104+
static inline void execmem_cache_make_ro(void) { }
99105
#endif
100106

101107
/**

mm/execmem.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,34 @@ static void *__execmem_cache_alloc(struct execmem_range *range, size_t size)
254254
return ptr;
255255
}
256256

257+
static bool execmem_cache_rox = false;
258+
259+
void execmem_cache_make_ro(void)
260+
{
261+
struct maple_tree *free_areas = &execmem_cache.free_areas;
262+
struct maple_tree *busy_areas = &execmem_cache.busy_areas;
263+
MA_STATE(mas_free, free_areas, 0, ULONG_MAX);
264+
MA_STATE(mas_busy, busy_areas, 0, ULONG_MAX);
265+
struct mutex *mutex = &execmem_cache.mutex;
266+
void *area;
267+
268+
execmem_cache_rox = true;
269+
270+
mutex_lock(mutex);
271+
272+
mas_for_each(&mas_free, area, ULONG_MAX) {
273+
unsigned long pages = mas_range_len(&mas_free) >> PAGE_SHIFT;
274+
set_memory_ro(mas_free.index, pages);
275+
}
276+
277+
mas_for_each(&mas_busy, area, ULONG_MAX) {
278+
unsigned long pages = mas_range_len(&mas_busy) >> PAGE_SHIFT;
279+
set_memory_ro(mas_busy.index, pages);
280+
}
281+
282+
mutex_unlock(mutex);
283+
}
284+
257285
static int execmem_cache_populate(struct execmem_range *range, size_t size)
258286
{
259287
unsigned long vm_flags = VM_ALLOW_HUGE_VMAP;
@@ -274,9 +302,15 @@ static int execmem_cache_populate(struct execmem_range *range, size_t size)
274302
/* fill memory with instructions that will trap */
275303
execmem_fill_trapping_insns(p, alloc_size, /* writable = */ true);
276304

277-
err = set_memory_rox((unsigned long)p, vm->nr_pages);
278-
if (err)
279-
goto err_free_mem;
305+
if (execmem_cache_rox) {
306+
err = set_memory_rox((unsigned long)p, vm->nr_pages);
307+
if (err)
308+
goto err_free_mem;
309+
} else {
310+
err = set_memory_x((unsigned long)p, vm->nr_pages);
311+
if (err)
312+
goto err_free_mem;
313+
}
280314

281315
err = execmem_cache_add(p, alloc_size);
282316
if (err)

0 commit comments

Comments
 (0)