Messages in this thread Patch in this message | | | Date | Thu, 20 Nov 2008 17:05:37 +0100 | From | Takashi Iwai <> | Subject | Re: vm86 segfaults with NX bit |
| |
At Thu, 20 Nov 2008 17:00:03 +0100, I wrote: > > At Thu, 20 Nov 2008 15:58:08 +0000, > Alan Cox wrote: > > > > > Also, when NX bit is reset for the first 1MB (or smaller) in > > > do_sys_vm86(), it also works as expected. But I have little clue > > > where to restore the bit again. > > > > > > Any good suggestions / solutions? > > > > Does it behave if you clear NX just for 640K-1MB, and page 0 ? > > Yes.
Ah, well, that's not exactly what I tested. I cleared NX on all 1MB pages like the patch below.
thanks,
Takashi
--- diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 4eeb5cf..60b00d0 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -192,6 +192,45 @@ out: flush_tlb(); } +#ifdef CONFIG_X86_PAE +static void mark_nx(struct mm_struct *mm, int set) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + spinlock_t *ptl; + int i; + + if (!(__supported_pte_mask & _PAGE_NX)) + return; + + pgd = pgd_offset(mm, 0); + if (pgd_none_or_clear_bad(pgd)) + goto out; + pud = pud_offset(pgd, 0); + if (pud_none_or_clear_bad(pud)) + goto out; + pmd = pmd_offset(pud, 0); + if (pmd_none_or_clear_bad(pmd)) + goto out; + pte = pte_offset_map_lock(mm, pmd, 0, &ptl); + for (i = 0; i < 256; i++) { + if (pte_present(*pte)) { + if (set) + set_pte(pte, __pte(pte_val(*pte) | _PAGE_NX)); + else + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_NX)); + } + pte++; + } + pte_unmap_unlock(pte, ptl); +out: + flush_tlb(); +} +#else +#define mark_nx(mm,x) do { } while (0) +#endif static int do_vm86_irq_handling(int subfunction, int irqnumber); @@ -335,6 +374,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk tsk->thread.screen_bitmap = info->screen_bitmap; if (info->flags & VM86_SCREEN_BITMAP) mark_screen_rdonly(tsk->mm); + mark_nx(tsk->mm, 0); /*call audit_syscall_exit since we do not exit via the normal paths */ if (unlikely(current->audit_context))
| |