lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <e5ff379e-b679-4513-b390-fa9b604999f4@kernel.org>
Date: Mon, 17 Nov 2025 13:04:39 +1000
From: Greg Ungerer <gerg@...nel.org>
To: Daniel Palmer <daniel@...ngy.jp>, geert@...ux-m68k.org,
 linux-m68k@...ts.linux-m68k.org
Cc: linux-kernel@...r.kernel.org
Subject: Re: [PATCH] m68k: Implement kernel memory protection

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@...ngy.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@...ux-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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ