x86/alternatives: Provide text_poke_copy_locked()
authorThomas Gleixner <tglx@linutronix.de>
Thu, 15 Sep 2022 11:11:20 +0000 (13:11 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 17 Oct 2022 14:41:11 +0000 (16:41 +0200)
The upcoming call thunk patching must hold text_mutex and needs access to
text_poke_copy(), which takes text_mutex.

Provide a _locked postfixed variant to expose the inner workings.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20220915111147.159977224@infradead.org
arch/x86/include/asm/text-patching.h
arch/x86/kernel/alternative.c

index 1cc15528ce29bab81582b4d23c02ba46c9309e49..f4b87f08f5c50d6083977f22d0043c318def3002 100644 (file)
@@ -45,6 +45,7 @@ extern void *text_poke(void *addr, const void *opcode, size_t len);
 extern void text_poke_sync(void);
 extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len);
 extern void *text_poke_copy(void *addr, const void *opcode, size_t len);
+extern void *text_poke_copy_locked(void *addr, const void *opcode, size_t len, bool core_ok);
 extern void *text_poke_set(void *addr, int c, size_t len);
 extern int poke_int3_handler(struct pt_regs *regs);
 extern void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate);
index 5cadcea035e044b47972675f0bd9792b8fc46fc0..fad3c0e4838eaeb5d3df455bf178a90e1b0b2701 100644 (file)
@@ -1236,27 +1236,15 @@ void *text_poke_kgdb(void *addr, const void *opcode, size_t len)
        return __text_poke(text_poke_memcpy, addr, opcode, len);
 }
 
-/**
- * text_poke_copy - Copy instructions into (an unused part of) RX memory
- * @addr: address to modify
- * @opcode: source of the copy
- * @len: length to copy, could be more than 2x PAGE_SIZE
- *
- * Not safe against concurrent execution; useful for JITs to dump
- * new code blocks into unused regions of RX memory. Can be used in
- * conjunction with synchronize_rcu_tasks() to wait for existing
- * execution to quiesce after having made sure no existing functions
- * pointers are live.
- */
-void *text_poke_copy(void *addr, const void *opcode, size_t len)
+void *text_poke_copy_locked(void *addr, const void *opcode, size_t len,
+                           bool core_ok)
 {
        unsigned long start = (unsigned long)addr;
        size_t patched = 0;
 
-       if (WARN_ON_ONCE(core_kernel_text(start)))
+       if (WARN_ON_ONCE(!core_ok && core_kernel_text(start)))
                return NULL;
 
-       mutex_lock(&text_mutex);
        while (patched < len) {
                unsigned long ptr = start + patched;
                size_t s;
@@ -1266,6 +1254,25 @@ void *text_poke_copy(void *addr, const void *opcode, size_t len)
                __text_poke(text_poke_memcpy, (void *)ptr, opcode + patched, s);
                patched += s;
        }
+       return addr;
+}
+
+/**
+ * text_poke_copy - Copy instructions into (an unused part of) RX memory
+ * @addr: address to modify
+ * @opcode: source of the copy
+ * @len: length to copy, could be more than 2x PAGE_SIZE
+ *
+ * Not safe against concurrent execution; useful for JITs to dump
+ * new code blocks into unused regions of RX memory. Can be used in
+ * conjunction with synchronize_rcu_tasks() to wait for existing
+ * execution to quiesce after having made sure no existing functions
+ * pointers are live.
+ */
+void *text_poke_copy(void *addr, const void *opcode, size_t len)
+{
+       mutex_lock(&text_mutex);
+       addr = text_poke_copy_locked(addr, opcode, len, false);
        mutex_unlock(&text_mutex);
        return addr;
 }