Skip to content

Commit

Permalink
execmem: add API for temporal remapping as RW and restoring ROX after…
Browse files Browse the repository at this point in the history
…wards

Using a writable copy for ROX memory is cumbersome and error prone.

Add API that allow temporarily remapping of ranges in the ROX cache as
writable  and then restoring their read-only-execute permissions.

This API will be later used in modules code and will allow removing nasty
games with writable copy in alternatives patching on x86.

The restoring of the ROX permissions relies on the ability of architecture
to reconstruct large pages in its set_memory_rox() method.

Signed-off-by: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250126074733.1384926-6-rppt@kernel.org
  • Loading branch information
Mike Rapoport (Microsoft) authored and Peter Zijlstra committed Feb 3, 2025
1 parent 925f426 commit 05e555b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
31 changes: 31 additions & 0 deletions include/linux/execmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,37 @@ enum execmem_range_flags {
* Architectures that use EXECMEM_ROX_CACHE must implement this.
*/
void execmem_fill_trapping_insns(void *ptr, size_t size, bool writable);

/**
* execmem_make_temp_rw - temporarily remap region with read-write
* permissions
* @ptr: address of the region to remap
* @size: size of the region to remap
*
* Remaps a part of the cached large page in the ROX cache in the range
* [@ptr, @ptr + @size) as writable and not executable. The caller must
* have exclusive ownership of this range and ensure nothing will try to
* execute code in this range.
*
* Return: 0 on success or negative error code on failure.
*/
int execmem_make_temp_rw(void *ptr, size_t size);

/**
* execmem_restore_rox - restore read-only-execute permissions
* @ptr: address of the region to remap
* @size: size of the region to remap
*
* Restores read-only-execute permissions on a range [@ptr, @ptr + @size)
* after it was temporarily remapped as writable. Relies on architecture
* implementation of set_memory_rox() to restore mapping using large pages.
*
* Return: 0 on success or negative error code on failure.
*/
int execmem_restore_rox(void *ptr, size_t size);
#else
static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; }
static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; }
#endif

/**
Expand Down
22 changes: 22 additions & 0 deletions mm/execmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,28 @@ static bool execmem_cache_free(void *ptr)

return true;
}

int execmem_make_temp_rw(void *ptr, size_t size)
{
unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long addr = (unsigned long)ptr;
int ret;

ret = set_memory_nx(addr, nr);
if (ret)
return ret;

return set_memory_rw(addr, nr);
}

int execmem_restore_rox(void *ptr, size_t size)
{
unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long addr = (unsigned long)ptr;

return set_memory_rox(addr, nr);
}

#else /* CONFIG_ARCH_HAS_EXECMEM_ROX */
static void *execmem_cache_alloc(struct execmem_range *range, size_t size)
{
Expand Down

0 comments on commit 05e555b

Please sign in to comment.