Skip to content

Commit e34d43f

Browse files
committed
execmem: add API for temporal remapping as RW and restoring ROX afterwards
jira LE-4694 Rebuild_History Non-Buildable kernel-6.12.0-55.43.1.el10_0 commit-author Mike Rapoport (Microsoft) <rppt@kernel.org> commit 05e555b 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 (cherry picked from commit 05e555b) Signed-off-by: Jonathan Maple <jmaple@ciq.com>
1 parent 32a2026 commit e34d43f

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

include/linux/execmem.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,37 @@ enum execmem_range_flags {
6565
* Architectures that use EXECMEM_ROX_CACHE must implement this.
6666
*/
6767
void execmem_fill_trapping_insns(void *ptr, size_t size, bool writable);
68+
69+
/**
70+
* execmem_make_temp_rw - temporarily remap region with read-write
71+
* permissions
72+
* @ptr: address of the region to remap
73+
* @size: size of the region to remap
74+
*
75+
* Remaps a part of the cached large page in the ROX cache in the range
76+
* [@ptr, @ptr + @size) as writable and not executable. The caller must
77+
* have exclusive ownership of this range and ensure nothing will try to
78+
* execute code in this range.
79+
*
80+
* Return: 0 on success or negative error code on failure.
81+
*/
82+
int execmem_make_temp_rw(void *ptr, size_t size);
83+
84+
/**
85+
* execmem_restore_rox - restore read-only-execute permissions
86+
* @ptr: address of the region to remap
87+
* @size: size of the region to remap
88+
*
89+
* Restores read-only-execute permissions on a range [@ptr, @ptr + @size)
90+
* after it was temporarily remapped as writable. Relies on architecture
91+
* implementation of set_memory_rox() to restore mapping using large pages.
92+
*
93+
* Return: 0 on success or negative error code on failure.
94+
*/
95+
int execmem_restore_rox(void *ptr, size_t size);
96+
#else
97+
static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; }
98+
static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; }
6899
#endif
69100

70101
/**

mm/execmem.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,28 @@ static bool execmem_cache_free(void *ptr)
319319

320320
return true;
321321
}
322+
323+
int execmem_make_temp_rw(void *ptr, size_t size)
324+
{
325+
unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT;
326+
unsigned long addr = (unsigned long)ptr;
327+
int ret;
328+
329+
ret = set_memory_nx(addr, nr);
330+
if (ret)
331+
return ret;
332+
333+
return set_memory_rw(addr, nr);
334+
}
335+
336+
int execmem_restore_rox(void *ptr, size_t size)
337+
{
338+
unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT;
339+
unsigned long addr = (unsigned long)ptr;
340+
341+
return set_memory_rox(addr, nr);
342+
}
343+
322344
#else /* CONFIG_ARCH_HAS_EXECMEM_ROX */
323345
static void *execmem_cache_alloc(struct execmem_range *range, size_t size)
324346
{

0 commit comments

Comments
 (0)