Re: [PATCH 2/2] No-exec support for ppc64

Benjamin Herrenschmidt
2005-03-09T03:06:49Z

On Tue, 2005-03-08 at 17:13 -0600, Jake Moilanen wrote:

> diff -puN arch/ppc64/kernel/iSeries_setup.c~nx-kernel-ppc64 arch/ppc64/kernel/iSeries_setup.c
> --- linux-2.6-bk/arch/ppc64/kernel/iSeries_setup.c~nx-kernel-ppc64 2005-03-08 16:08:57 -06:00
> +++ linux-2.6-bk-moilanen/arch/ppc64/kernel/iSeries_setup.c 2005-03-08 16:08:57 -06:00
> @@ -624,6 +624,7 @@ static void __init iSeries_bolt_kernel(u
> {
> unsigned long pa;
> unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
> + unsigned long tmp_mode;
> HPTE hpte;
>
> for (pa = saddr; pa < eaddr ;pa += PAGE_SIZE) {
> @@ -632,6 +633,12 @@ static void __init iSeries_bolt_kernel(u
> unsigned long va = (vsid << 28) | (pa & 0xfffffff);
> unsigned long vpn = va >> PAGE_SHIFT;
> unsigned long slot = HvCallHpt_findValid(&hpte, vpn);
> +
> + tmp_mode = mode_rw;
> +
> + /* Make non-kernel text non-executable */
> + if (!is_kernel_text(ea))
> + tmp_mode = mode_rw | HW_NO_EXEC;
>
> if (hpte.dw0.dw0.v) {
> /* HPTE exists, so just bolt it */

tmp_mode doesn't seem to be ever used here ...

> /* Free memory returned from module_alloc */
> diff -puN arch/ppc64/mm/fault.c~nx-kernel-ppc64 arch/ppc64/mm/fault.c
> --- linux-2.6-bk/arch/ppc64/mm/fault.c~nx-kernel-ppc64 2005-03-08 16:08:57 -06:00
> +++ linux-2.6-bk-moilanen/arch/ppc64/mm/fault.c 2005-03-08 16:08:57 -06:00
> @@ -76,6 +76,21 @@ static int store_updates_sp(struct pt_re
> return 0;
> }
>
> +pte_t *lookup_address(unsigned long address)
> +{
> + pgd_t *pgd = pgd_offset_k(address);
> + pmd_t *pmd;
> +
> + if (pgd_none(*pgd))
> + return NULL;
> +
> + pmd = pmd_offset(pgd, address);
> + if (pmd_none(*pmd))
> + return NULL;
> +
> + return pte_offset_kernel(pmd, address);
> +}

Use find_linux_pte() here (asm-ppc64/pgtable.h). It will return NULL of
the PTE is not present too, so no need to dbl check that. That way, I
won't have to fix your copy of the function when I get the proper 4L
headers patch in ;)

> /*
> * The error_code parameter is
> * - DSISR for a non-SLB data access fault,
> @@ -94,6 +109,7 @@ int do_page_fault(struct pt_regs *regs,
> unsigned long is_write = error_code & 0x02000000;
> unsigned long trap = TRAP(regs);
> unsigned long is_exec = trap == 0x400;
> + pte_t *ptep;
>
> BUG_ON((trap == 0x380) || (trap == 0x480));
>
> @@ -253,6 +269,15 @@ bad_area_nosemaphore:
> info.si_addr = (void __user *) address;
> force_sig_info(SIGSEGV, &info, current);
> return 0;
> + }
> +
> + ptep = lookup_address(address);
> +
> + if (ptep && pte_present(*ptep) && !pte_exec(*ptep)) {
> + if (printk_ratelimit())
> + printk(KERN_CRIT "kernel tried to execute NX-protected page - exploit attempt? (uid: %d)\n", current->uid);
> + show_stack(current, (unsigned long *)__get_SP());
> + do_exit(SIGKILL);
> }

Can you try to limit to 80 columns ? (I know, I'm not the best for that
neither, but I'm trying to cure myself here, I promise my next rewrite
of radeonfb will be fully 80-columns safe :)