From: Greg Ungerer <gerg@kernel.org>
To: Daniel Palmer <daniel@thingy.jp>,
geert@linux-m68k.org, linux-m68k@lists.linux-m68k.org
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH] m68k: Implement kernel memory protection
Date: Mon, 17 Nov 2025 13:04:39 +1000 [thread overview]
Message-ID: <e5ff379e-b679-4513-b390-fa9b604999f4@kernel.org> (raw)
In-Reply-To: <20251116220508.1513445-1-daniel@thingy.jp>
Hi Daniel,
On 17/11/25 08:05, Daniel Palmer wrote:
> Every time I boot linux on my various m68k machines I see
> "This architecture does not have kernel memory protection."
>
> I wondered why this was as some of my machines even have one of
> those fancy MMU doodads. I worked out it was because we don't have
> CONFIG_ARCH_HAS_STRICT_KERNEL_RWX, found kernel_set_cachemode()
> seemed like it had the code for setting some extra flags for
> kernel pages and turned that into something that sets write
> protect for kernel pages.
>
> So now we can make CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y and
> provide mark_rodata_ro() to mark the kernel text and rodata
> as write protected.
>
> The test enabled by CONFIG_DEBUG_RODATA_TEST=y says this is
> working, but I've only tested on the virt machine.
>
> Signed-off-by: Daniel Palmer <daniel@thingy.jp>
Seems to work fine on real ColdFire hardware (tested on an M5475 -
that is one that has an MMU):
...
VFS: Mounted root (romfs filesystem) readonly on device 31:0.
Freeing unused kernel image (initmem) memory: 88K
Write protecting kernel text: 0x22000 - 0x393f70
Write protecting kernel read-only data: 0x394000 - 0x450000
Run /sbin/init as init process
Run /etc/init as init process
Run /bin/init as init process
process '/bin/init' started with executable stack
...
Tested-by: Greg Ungerer <gerg@linux-m68k.org>
Regards
Greg
> ---
> arch/m68k/Kconfig | 1 +
> arch/m68k/mm/init.c | 69 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 70 insertions(+)
>
> diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
> index 11835eb59d94..2137fd19ffbd 100644
> --- a/arch/m68k/Kconfig
> +++ b/arch/m68k/Kconfig
> @@ -8,6 +8,7 @@ config M68K
> select ARCH_HAS_CPU_FINALIZE_INIT if MMU
> select ARCH_HAS_CURRENT_STACK_POINTER
> select ARCH_HAS_DMA_PREP_COHERENT if M68K_NONCOHERENT_DMA && !COLDFIRE
> + select ARCH_HAS_STRICT_KERNEL_RWX if MMU
> select ARCH_HAS_SYNC_DMA_FOR_DEVICE if M68K_NONCOHERENT_DMA
> select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
> select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
> diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
> index 488411af1b3f..bc1147f25624 100644
> --- a/arch/m68k/mm/init.c
> +++ b/arch/m68k/mm/init.c
> @@ -123,3 +123,72 @@ void __init mem_init(void)
> {
> init_pointer_tables();
> }
> +
> +#ifdef CONFIG_MMU
> +/*
> + * Based on (basically copy/pasted) kernel_set_cachemode() because
> + * presumably that is correct and covers the required differences.
> + */
> +static void __mark_ro_data(unsigned long virtaddr, ssize_t size)
> +{
> + pgd_t *pgd_dir;
> + p4d_t *p4d_dir;
> + pud_t *pud_dir;
> + pmd_t *pmd_dir;
> + pte_t *pte_dir;
> +
> + while (size > 0) {
> + pgd_dir = pgd_offset_k(virtaddr);
> + p4d_dir = p4d_offset(pgd_dir, virtaddr);
> + pud_dir = pud_offset(p4d_dir, virtaddr);
> + if (pud_bad(*pud_dir)) {
> + pud_clear(pud_dir);
> + return;
> + }
> + pmd_dir = pmd_offset(pud_dir, virtaddr);
> +
> +#if CONFIG_PGTABLE_LEVELS == 3
> + if (CPU_IS_020_OR_030) {
> + unsigned long pmd = pmd_val(*pmd_dir);
> +
> + if ((pmd & _DESCTYPE_MASK) == _PAGE_PRESENT) {
> + *pmd_dir = __pmd(pmd | _PAGE_RONLY);
> + virtaddr += PMD_SIZE;
> + size -= PMD_SIZE;
> + continue;
> + }
> + }
> +#endif
> +
> + if (pmd_bad(*pmd_dir)) {
> + pmd_clear(pmd_dir);
> + return;
> + }
> + pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
> +
> + set_pte(pte_dir, pte_wrprotect(*pte_dir));
> + virtaddr += PAGE_SIZE;
> + size -= PAGE_SIZE;
> + }
> +}
> +
> +void mark_rodata_ro(void)
> +{
> + unsigned long start;
> + unsigned long end;
> +
> + /* kernel text - kernel_pg_dir lives in the first page, so skip that */
> + start = (unsigned long) _stext + PAGE_SIZE;
> + end = (unsigned long) _etext;
> + pr_info("Write protecting kernel text: 0x%lx - 0x%lx\n", start, end);
> + __mark_ro_data(start, end - start);
> +
> + /* ro data */
> + start = (unsigned long) __start_rodata;
> + end = (unsigned long) __end_rodata;
> + pr_info("Write protecting kernel read-only data: 0x%lx - 0x%lx\n", start, end);
> + __mark_ro_data(start, end - start);
> +
> + flush_tlb_all();
> +}
> +#endif
next prev parent reply other threads:[~2025-11-17 3:04 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-16 22:05 Daniel Palmer
2025-11-17 3:04 ` Greg Ungerer [this message]
2025-11-17 9:42 ` Daniel Palmer
2025-11-17 17:41 ` Michael Schmitz
2025-11-17 22:01 ` Daniel Palmer
2025-11-17 23:14 ` Michael Schmitz
2025-11-18 10:55 ` Daniel Palmer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e5ff379e-b679-4513-b390-fa9b604999f4@kernel.org \
--to=gerg@kernel.org \
--cc=daniel@thingy.jp \
--cc=geert@linux-m68k.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-m68k@lists.linux-m68k.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®