From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754638AbYKTQFs (ORCPT ); Thu, 20 Nov 2008 11:05:48 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752537AbYKTQFj (ORCPT ); Thu, 20 Nov 2008 11:05:39 -0500 Received: from mx2.suse.de ([195.135.220.15]:36398 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751948AbYKTQFj (ORCPT ); Thu, 20 Nov 2008 11:05:39 -0500 Date: Thu, 20 Nov 2008 17:05:37 +0100 Message-ID: From: Takashi Iwai To: Alan Cox Cc: linux-kernel@vger.kernel.org Subject: Re: vm86 segfaults with NX bit In-Reply-To: References: <20081120155808.19439807@lxorguk.ukuu.org.uk> User-Agent: Wanderlust/2.12.0 (Your Wildest Dreams) SEMI/1.14.6 (Maruoka) FLIM/1.14.7 (=?ISO-8859-4?Q?Sanj=F2?=) APEL/10.6 Emacs/22.3 (x86_64-suse-linux-gnu) MULE/5.0 (SAKAKI) MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: text/plain; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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))