An upcoming patch will add the SHF_MERGE flag to x86 __jump_table and
__bug_table so their entry sizes can be defined in inline asm.

However, those sections have SHF_WRITE, which the Clang linker (lld)
explicitly forbids combining with SHF_MERGE.

Those sections are modified at runtime and must remain writable.  While
SHF_WRITE is ignored by vmlinux, it's still needed for modules.

To work around the linker interference, remove SHF_WRITE during
compilation and restore it after linking the module.

Cc: Masahiro Yamada <masahi...@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org>
---
 arch/Kconfig                      |  3 +++
 arch/x86/Kconfig                  |  1 +
 arch/x86/include/asm/bug.h        |  4 ++--
 arch/x86/include/asm/jump_label.h |  2 +-
 scripts/Makefile.modfinal         | 19 ++++++++++++++-----
 5 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index a3308a220f86..350ea5df5e8d 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1314,6 +1314,9 @@ config HAVE_NOINSTR_HACK
 config HAVE_NOINSTR_VALIDATION
        bool
 
+config NEED_MODULE_PERMISSIONS_FIX
+       bool
+
 config HAVE_UACCESS_VALIDATION
        bool
        select OBJTOOL
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 71019b3b54ea..62faa62b5959 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -310,6 +310,7 @@ config X86
        select HOTPLUG_SPLIT_STARTUP            if SMP && X86_32
        select IRQ_FORCED_THREADING
        select LOCK_MM_AND_FIND_VMA
+       select NEED_MODULE_PERMISSIONS_FIX
        select NEED_PER_CPU_EMBED_FIRST_CHUNK
        select NEED_PER_CPU_PAGE_FIRST_CHUNK
        select NEED_SG_DMA_LENGTH
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index 8593976b32cb..59e155ee3c76 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -42,7 +42,7 @@
 #define _BUG_FLAGS(cond_str, ins, flags, extra)                                
\
 do {                                                                   \
        asm_inline volatile("1:\t" ins "\n"                             \
-                    ".pushsection __bug_table,\"aw\"\n"                \
+                    ".pushsection __bug_table,\"a\"\n"                 \
                     "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
                     "\t"  __BUG_REL(%c0) "\t# bug_entry::file\n"       \
                     "\t.word %c1"        "\t# bug_entry::line\n"       \
@@ -60,7 +60,7 @@ do {                                                          
        \
 #define _BUG_FLAGS(cond_str, ins, flags, extra)                                
\
 do {                                                                   \
        asm_inline volatile("1:\t" ins "\n"                             \
-                    ".pushsection __bug_table,\"aw\"\n"                \
+                    ".pushsection __bug_table,\"a\"\n"                 \
                     "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
                     "\t.word %c0"        "\t# bug_entry::flags\n"      \
                     "\t.org 2b+%c1\n"                                  \
diff --git a/arch/x86/include/asm/jump_label.h 
b/arch/x86/include/asm/jump_label.h
index 61dd1dee7812..cd21554b3675 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -13,7 +13,7 @@
 #include <linux/types.h>
 
 #define JUMP_TABLE_ENTRY(key, label)                   \
-       ".pushsection __jump_table,  \"aw\" \n\t"       \
+       ".pushsection __jump_table,  \"a\"\n\t"         \
        _ASM_ALIGN "\n\t"                               \
        ".long 1b - . \n\t"                             \
        ".long " label " - . \n\t"                      \
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 542ba462ed3e..7a888e1ff70f 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -28,12 +28,24 @@ ccflags-remove-y := $(CC_FLAGS_CFI)
 .module-common.o: $(srctree)/scripts/module-common.c FORCE
        $(call if_changed_rule,cc_o_c)
 
+ifdef CONFIG_NEED_MODULE_PERMISSIONS_FIX
+cmd_fix_mod_permissions =                                              \
+       $(OBJCOPY) --set-section-flags __jump_table=alloc,data          \
+                  --set-section-flags __bug_table=alloc,data $@        \
+                  --set-section-flags .static_call_sites=alloc,data $@
+endif
+
 quiet_cmd_ld_ko_o = LD [M]  $@
       cmd_ld_ko_o =                                                    \
        $(LD) -r $(KBUILD_LDFLAGS)                                      \
                $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE)              \
                -T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^)
 
+define rule_ld_ko_o
+       $(call cmd_and_savecmd,ld_ko_o)
+       $(call cmd,fix_mod_permissions)
+endef
+
 quiet_cmd_btf_ko = BTF [M] $@
       cmd_btf_ko =                                                     \
        if [ ! -f $(objtree)/vmlinux ]; then                            \
@@ -46,14 +58,11 @@ quiet_cmd_btf_ko = BTF [M] $@
 # Same as newer-prereqs, but allows to exclude specified extra dependencies
 newer_prereqs_except = $(filter-out $(PHONY) $(1),$?)
 
-# Same as if_changed, but allows to exclude specified extra dependencies
-if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check),      \
-       $(cmd);                                                              \
-       printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
+if_changed_rule_except = $(if $(call 
newer_prereqs_except,$(2))$(cmd-check),$(rule_$(1)),@:)
 
 # Re-generate module BTFs if either module's .ko or vmlinux changed
 %.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and 
$(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
-       +$(call if_changed_except,ld_ko_o,$(objtree)/vmlinux)
+       +$(call if_changed_rule_except,ld_ko_o,$(objtree)/vmlinux)
 ifdef CONFIG_DEBUG_INFO_BTF_MODULES
        +$(if $(newer-prereqs),$(call cmd,btf_ko))
 endif
-- 
2.49.0


Reply via email to