All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arun Sharma <arun.sharma@intel.com>
To: linux-ia64@vger.kernel.org
Subject: [PATCH] ia32 support for NX when sigaction->sa_restorer == NULL
Date: Fri, 10 Sep 2004 16:17:54 +0000	[thread overview]
Message-ID: <4141D3B2.2030106@intel.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 366 bytes --]


When userland doesn't specify sigaction->sa_restorer, we try to put
the restorer code on the stack. But this breaks ia32 binaries with
non-executable stacks. We now put the restorer code on a gate page.

We still leave the sigreturn code on the stack due to backward 
compatibility concerns with ia32 gdb.

This issue was primarily seen with debian glibc.

	-Arun


[-- Attachment #2: ive-gate-page-3.patch --]
[-- Type: text/plain, Size: 9306 bytes --]

When userland doesn't specify sigaction->sa_restorer, we try to put
the restorer code on the stack. But this breaks ia32 binaries with
non-executable stacks. We now put the restorer code on a gate page.

Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>

 arch/ia64/ia32/binfmt_elf32.c |   39 +++++++++++++++++++++++++++++++++++++++
 arch/ia64/ia32/ia32_signal.c  |   33 ++++++++++++++++++++++-----------
 arch/ia64/ia32/ia32_support.c |   28 +++++++++++++++++++++++++---
 arch/ia64/ia32/ia32priv.h     |   11 ++++++++---
 arch/ia64/mm/init.c           |    2 +-
 include/asm-ia64/ia32.h       |    2 +-
 6 files changed, 96 insertions(+), 19 deletions(-)

diff -purN -X dontdiff linux-2.6.8.ori/arch/ia64/ia32/binfmt_elf32.c linux-2.6.8/arch/ia64/ia32/binfmt_elf32.c
--- linux-2.6.8.ori/arch/ia64/ia32/binfmt_elf32.c	2004-08-16 15:36:30.000000000 +0800
+++ linux-2.6.8/arch/ia64/ia32/binfmt_elf32.c	2004-09-09 18:31:47.000000000 +0800
@@ -48,6 +48,7 @@ static void elf32_set_personality (void)
 
 extern struct page *ia32_shared_page[];
 extern unsigned long *ia32_gdt;
+extern struct page *ia32_gate_page;
 
 struct page *
 ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int *type)
@@ -59,10 +60,25 @@ ia32_install_shared_page (struct vm_area
 	return pg;
 }
 
+struct page *
+ia32_install_gate_page (struct vm_area_struct *vma, unsigned long address, int *type)
+{
+	struct page *pg = ia32_gate_page;
+	get_page(pg);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return pg;
+}
+
+
 static struct vm_operations_struct ia32_shared_page_vm_ops = {
 	.nopage = ia32_install_shared_page
 };
 
+static struct vm_operations_struct ia32_gate_page_vm_ops = {
+	.nopage = ia32_install_gate_page
+};
+
 void
 ia64_elf32_init (struct pt_regs *regs)
 {
@@ -90,6 +106,29 @@ ia64_elf32_init (struct pt_regs *regs)
 	}
 
 	/*
+	 * When user stack is not executable, push sigreturn code to stack makes
+	 * segmentation fault raised when returning to kernel. So now sigreturn
+	 * code is locked in specific gate page, which is pointed by pretcode
+	 * when setup_frame_ia32
+	 */
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (vma) {
+		memset(vma, 0, sizeof(*vma));
+		vma->vm_mm = current->mm;
+		vma->vm_start = IA32_GATE_OFFSET;
+		vma->vm_end = vma->vm_start + PAGE_SIZE;
+		vma->vm_page_prot = PAGE_COPY_EXEC;
+		vma->vm_flags = VM_READ | VM_MAYREAD | VM_EXEC
+				| VM_MAYEXEC | VM_RESERVED;
+		vma->vm_ops = &ia32_gate_page_vm_ops;
+		down_write(&current->mm->mmap_sem);
+		{
+			insert_vm_struct(current->mm, vma);
+		}
+		up_write(&current->mm->mmap_sem);
+	}
+
+	/*
 	 * Install LDT as anonymous memory.  This gives us all-zero segment descriptors
 	 * until a task modifies them via modify_ldt().
 	 */
diff -purN -X dontdiff linux-2.6.8.ori/arch/ia64/ia32/ia32priv.h linux-2.6.8/arch/ia64/ia32/ia32priv.h
--- linux-2.6.8.ori/arch/ia64/ia32/ia32priv.h	2004-08-16 15:36:30.000000000 +0800
+++ linux-2.6.8/arch/ia64/ia32/ia32priv.h	2004-09-09 19:03:34.000000000 +0800
@@ -168,6 +168,9 @@ struct ia32_user_fxsr_struct {
 #define IA32_SA_HANDLER(ka)	((unsigned long) (ka)->sa.sa_handler & 0xffffffff)
 #define IA32_SA_RESTORER(ka)	((unsigned long) (ka)->sa.sa_handler >> 32)
 
+#define __IA32_NR_sigreturn 119
+#define __IA32_NR_rt_sigreturn 173
+
 struct sigaction32 {
        unsigned int sa_handler;		/* Really a pointer, but need to deal with 32 bits */
        unsigned int sa_flags;
@@ -324,14 +327,16 @@ struct old_linux32_dirent {
 
 #define IA32_PAGE_OFFSET	0xc0000000
 #define IA32_STACK_TOP		IA32_PAGE_OFFSET
+#define IA32_GATE_OFFSET	IA32_PAGE_OFFSET
+#define IA32_GATE_END		IA32_PAGE_OFFSET + PAGE_SIZE
 
 /*
  * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can
  * access them.
  */
-#define IA32_GDT_OFFSET		(IA32_PAGE_OFFSET)
-#define IA32_TSS_OFFSET		(IA32_PAGE_OFFSET + PAGE_SIZE)
-#define IA32_LDT_OFFSET		(IA32_PAGE_OFFSET + 2*PAGE_SIZE)
+#define IA32_GDT_OFFSET		(IA32_PAGE_OFFSET + PAGE_SIZE)
+#define IA32_TSS_OFFSET		(IA32_PAGE_OFFSET + 2*PAGE_SIZE)
+#define IA32_LDT_OFFSET		(IA32_PAGE_OFFSET + 3*PAGE_SIZE)
 
 #define ELF_EXEC_PAGESIZE	IA32_PAGE_SIZE
 
diff -purN -X dontdiff linux-2.6.8.ori/arch/ia64/ia32/ia32_signal.c linux-2.6.8/arch/ia64/ia32/ia32_signal.c
--- linux-2.6.8.ori/arch/ia64/ia32/ia32_signal.c	2004-06-17 15:55:32.000000000 +0800
+++ linux-2.6.8/arch/ia64/ia32/ia32_signal.c	2004-09-09 18:31:47.000000000 +0800
@@ -853,14 +853,19 @@ setup_frame_ia32 (int sig, struct k_siga
 		unsigned int restorer = IA32_SA_RESTORER(ka);
 		err |= __put_user(restorer, &frame->pretcode);
 	} else {
-		err |= __put_user((long)frame->retcode, &frame->pretcode);
-		/* This is popl %eax ; movl $,%eax ; int $0x80 */
-		err |= __put_user(0xb858, (short *)(frame->retcode+0));
-		err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2));
-		err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4));
-		err |= __put_user(0x80cd, (short *)(frame->retcode+6));
+		/* Pointing to restorer in ia32 gate page */
+		err |= __put_user(IA32_GATE_OFFSET, &frame->pretcode);
 	}
 
+	/* This is popl %eax ; movl $,%eax ; int $0x80
+	 * and there for historical reasons only.
+	 * See arch/i386/kernel/signal.c
+	 */
+
+	err |= __put_user(0xb858, (short *)(frame->retcode+0));
+	err |= __put_user(__IA32_NR_sigreturn, (int *)(frame->retcode+2));
+	err |= __put_user(0x80cd, (short *)(frame->retcode+6));
+
 	if (err)
 		goto give_sigsegv;
 
@@ -924,13 +929,19 @@ setup_rt_frame_ia32 (int sig, struct k_s
 		unsigned int restorer = IA32_SA_RESTORER(ka);
 		err |= __put_user(restorer, &frame->pretcode);
 	} else {
-		err |= __put_user((long)frame->retcode, &frame->pretcode);
-		/* This is movl $,%eax ; int $0x80 */
-		err |= __put_user(0xb8, (char *)(frame->retcode+0));
-		err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1));
-		err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+		/* Pointing to rt_restorer in ia32 gate page */
+		err |= __put_user(IA32_GATE_OFFSET + 8, &frame->pretcode);
 	}
 
+	/* This is movl $,%eax ; int $0x80
+	 * and there for historical reasons only.
+	 * See arch/i386/kernel/signal.c
+	 */
+
+	err |= __put_user(0xb8, (char *)(frame->retcode+0));
+	err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1));
+	err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+
 	if (err)
 		goto give_sigsegv;
 
diff -purN -X dontdiff linux-2.6.8.ori/arch/ia64/ia32/ia32_support.c linux-2.6.8/arch/ia64/ia32/ia32_support.c
--- linux-2.6.8.ori/arch/ia64/ia32/ia32_support.c	2004-08-16 15:36:30.000000000 +0800
+++ linux-2.6.8/arch/ia64/ia32/ia32_support.c	2004-09-09 18:31:47.000000000 +0800
@@ -33,6 +33,7 @@ struct exec_domain ia32_exec_domain;
 struct page *ia32_shared_page[NR_CPUS];
 unsigned long *ia32_boot_gdt;
 unsigned long *cpu_gdt_table[NR_CPUS];
+struct page *ia32_gate_page;
 
 static unsigned long
 load_desc (u16 selector)
@@ -155,7 +156,7 @@ ia32_gdt_init (void)
 /*
  * Setup IA32 GDT and TSS
  */
-void
+static void
 ia32_boot_gdt_init (void)
 {
 	unsigned long ldt_size;
@@ -166,12 +167,12 @@ ia32_boot_gdt_init (void)
 
 	/* CS descriptor in IA-32 (scrambled) format */
 	ia32_boot_gdt[__USER_CS >> 3]
-		= IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT,
+		= IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT,
 				      0xb, 1, 3, 1, 1, 1, 1);
 
 	/* DS descriptor in IA-32 (scrambled) format */
 	ia32_boot_gdt[__USER_DS >> 3]
-		= IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT,
+		= IA32_SEG_DESCRIPTOR(0, (IA32_GATE_END-1) >> IA32_PAGE_SHIFT,
 				      0x3, 1, 3, 1, 1, 1, 1);
 
 	ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
@@ -181,6 +182,27 @@ ia32_boot_gdt_init (void)
 						       0x2, 0, 3, 1, 1, 1, 0);
 }
 
+static void
+ia32_gate_page_init(void)
+{
+	unsigned long *sr;
+
+	ia32_gate_page = alloc_page(GFP_KERNEL);
+	sr = page_address(ia32_gate_page);
+	/* This is popl %eax ; movl $,%eax ; int $0x80 */
+	*sr++ = 0xb858 | (__IA32_NR_sigreturn << 16) | (0x80cdUL << 48);
+
+	/* This is movl $,%eax ; int $0x80 */
+	*sr = 0xb8 | (__IA32_NR_rt_sigreturn << 8) | (0x80cdUL << 40);
+}
+
+void
+ia32_mem_init(void)
+{
+	ia32_boot_gdt_init();
+	ia32_gate_page_init();
+}
+
 /*
  * Handle bad IA32 interrupt via syscall
  */
diff -purN -X dontdiff linux-2.6.8.ori/arch/ia64/mm/init.c linux-2.6.8/arch/ia64/mm/init.c
--- linux-2.6.8.ori/arch/ia64/mm/init.c	2004-08-16 15:36:30.000000000 +0800
+++ linux-2.6.8/arch/ia64/mm/init.c	2004-09-09 18:31:47.000000000 +0800
@@ -585,6 +585,6 @@ mem_init (void)
 	setup_gate();
 
 #ifdef CONFIG_IA32_SUPPORT
-	ia32_boot_gdt_init();
+	ia32_mem_init();
 #endif
 }
diff -purN -X dontdiff linux-2.6.8.ori/include/asm-ia64/ia32.h linux-2.6.8/include/asm-ia64/ia32.h
--- linux-2.6.8.ori/include/asm-ia64/ia32.h	2004-08-16 15:36:43.000000000 +0800
+++ linux-2.6.8/include/asm-ia64/ia32.h	2004-09-09 18:31:47.000000000 +0800
@@ -14,7 +14,7 @@
 # ifdef CONFIG_IA32_SUPPORT
 
 extern void ia32_cpu_init (void);
-extern void ia32_boot_gdt_init (void);
+extern void ia32_mem_init (void);
 extern void ia32_gdt_init (void);
 extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
 extern int ia32_intercept (struct pt_regs *regs, unsigned long isr);

             reply	other threads:[~2004-09-10 16:17 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-09-10 16:17 Arun Sharma [this message]
2004-09-21 21:56 ` [PATCH] ia32 support for NX when sigaction->sa_restorer == NULL Andreas Schwab
2004-09-22  1:44 ` Arun Sharma
2004-09-22  7:22 ` Andreas Schwab

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=4141D3B2.2030106@intel.com \
    --to=arun.sharma@intel.com \
    --cc=linux-ia64@vger.kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.