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(¤t->mm->mmap_sem);
+ {
+ insert_vm_struct(current->mm, vma);
+ }
+ up_write(¤t->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);
next 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.