[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250121095739.986006-6-rppt@kernel.org>
Date: Tue, 21 Jan 2025 11:57:34 +0200
From: Mike Rapoport <rppt@...nel.org>
To: x86@...nel.org
Cc: Andrew Morton <akpm@...ux-foundation.org>,
Andy Lutomirski <luto@...nel.org>,
Anton Ivanov <anton.ivanov@...bridgegreys.com>,
Borislav Petkov <bp@...en8.de>,
Brendan Higgins <brendan.higgins@...ux.dev>,
Daniel Gomez <da.gomez@...sung.com>,
Daniel Thompson <danielt@...nel.org>,
Dave Hansen <dave.hansen@...ux.intel.com>,
David Gow <davidgow@...gle.com>,
Douglas Anderson <dianders@...omium.org>,
Ingo Molnar <mingo@...hat.com>,
Jason Wessel <jason.wessel@...driver.com>,
Jiri Kosina <jikos@...nel.org>,
Joe Lawrence <joe.lawrence@...hat.com>,
Johannes Berg <johannes@...solutions.net>,
Josh Poimboeuf <jpoimboe@...nel.org>,
"Kirill A. Shutemov" <kirill.shutemov@...ux.intel.com>,
Lorenzo Stoakes <lorenzo.stoakes@...cle.com>,
Luis Chamberlain <mcgrof@...nel.org>,
Mark Rutland <mark.rutland@....com>,
Masami Hiramatsu <mhiramat@...nel.org>,
Mike Rapoport <rppt@...nel.org>,
Miroslav Benes <mbenes@...e.cz>,
"H. Peter Anvin" <hpa@...or.com>,
Peter Zijlstra <peterz@...radead.org>,
Petr Mladek <pmladek@...e.com>,
Petr Pavlu <petr.pavlu@...e.com>,
Rae Moar <rmoar@...gle.com>,
Richard Weinberger <richard@....at>,
Sami Tolvanen <samitolvanen@...gle.com>,
Shuah Khan <shuah@...nel.org>,
Song Liu <song@...nel.org>,
Steven Rostedt <rostedt@...dmis.org>,
Thomas Gleixner <tglx@...utronix.de>,
kgdb-bugreport@...ts.sourceforge.net,
kunit-dev@...glegroups.com,
linux-kernel@...r.kernel.org,
linux-kselftest@...r.kernel.org,
linux-mm@...ck.org,
linux-modules@...r.kernel.org,
linux-trace-kernel@...r.kernel.org,
linux-um@...ts.infradead.org,
live-patching@...r.kernel.org
Subject: [PATCH v2 05/10] execmem: add API for temporal remapping as RW and restoring ROX afterwards
From: "Mike Rapoport (Microsoft)" <rppt@...nel.org>
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@...nel.org>
---
include/linux/execmem.h | 31 +++++++++++++++++++++++++++++++
mm/execmem.c | 22 ++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/include/linux/execmem.h b/include/linux/execmem.h
index 64130ae19690..65655a5d1be2 100644
--- a/include/linux/execmem.h
+++ b/include/linux/execmem.h
@@ -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
/**
diff --git a/mm/execmem.c b/mm/execmem.c
index 04b0bf1b5025..e6c4f5076ca8 100644
--- a/mm/execmem.c
+++ b/mm/execmem.c
@@ -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)
{
--
2.45.2
Powered by blists - more mailing lists