arm64: mm: Fix "rodata=on" when CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
authorWill Deacon <will@kernel.org>
Fri, 17 Nov 2023 13:14:22 +0000 (13:14 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 3 Dec 2023 06:33:05 +0000 (07:33 +0100)
[ Upstream commit acfa60dbe03802d6afd28401aa47801270e82021 ]

When CONFIG_RODATA_FULL_DEFAULT_ENABLED=y, passing "rodata=on" on the
kernel command-line (rather than "rodata=full") should turn off the
"full" behaviour, leaving writable linear aliases of read-only kernel
memory. Unfortunately, the option has no effect in this situation and
the only way to disable the "rodata=full" behaviour is to disable rodata
protection entirely by passing "rodata=off".

Fix this by parsing the "on" and "off" options in the arch code,
additionally enforcing that 'rodata_full' cannot be set without also
setting 'rodata_enabled', allowing us to simplify a couple of checks
in the process.

Fixes: 2e8cff0a0eee ("arm64: fix rodata=full")
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
Reviewed-by: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20231117131422.29663-1-will@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/arm64/include/asm/setup.h
arch/arm64/mm/pageattr.c

index f4af547ef54caa70a521387d442ffeb6d04a230b..2e4d7da74fb87a8444c516e343108f88f611336e 100644 (file)
@@ -21,9 +21,22 @@ static inline bool arch_parse_debug_rodata(char *arg)
        extern bool rodata_enabled;
        extern bool rodata_full;
 
-       if (arg && !strcmp(arg, "full")) {
+       if (!arg)
+               return false;
+
+       if (!strcmp(arg, "full")) {
+               rodata_enabled = rodata_full = true;
+               return true;
+       }
+
+       if (!strcmp(arg, "off")) {
+               rodata_enabled = rodata_full = false;
+               return true;
+       }
+
+       if (!strcmp(arg, "on")) {
                rodata_enabled = true;
-               rodata_full = true;
+               rodata_full = false;
                return true;
        }
 
index 8e2017ba5f1b114640544e1f01e0ebb399d074c7..924843f1f661bfe1ff5c6b8f9eff753872416040 100644 (file)
@@ -29,8 +29,8 @@ bool can_set_direct_map(void)
         *
         * KFENCE pool requires page-granular mapping if initialized late.
         */
-       return (rodata_enabled && rodata_full) || debug_pagealloc_enabled() ||
-               arm64_kfence_can_set_direct_map();
+       return rodata_full || debug_pagealloc_enabled() ||
+              arm64_kfence_can_set_direct_map();
 }
 
 static int change_page_range(pte_t *ptep, unsigned long addr, void *data)
@@ -105,8 +105,7 @@ static int change_memory_common(unsigned long addr, int numpages,
         * If we are manipulating read-only permissions, apply the same
         * change to the linear mapping of the pages that back this VM area.
         */
-       if (rodata_enabled &&
-           rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
+       if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
                            pgprot_val(clear_mask) == PTE_RDONLY)) {
                for (i = 0; i < area->nr_pages; i++) {
                        __change_memory_common((u64)page_address(area->pages[i]),