Commit 7ebc6034 authored by Kevin Tian's avatar Kevin Tian Committed by Tony Luck

[IA64] ia32compat: Put signal restorer code on a gate page

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: default avatarKevin Tian <kevin.tian@intel.com>
Signed-off-by: default avatarArun Sharma <arun.sharma@intel.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent f6c62004
...@@ -48,6 +48,7 @@ static void elf32_set_personality (void); ...@@ -48,6 +48,7 @@ static void elf32_set_personality (void);
extern struct page *ia32_shared_page[]; extern struct page *ia32_shared_page[];
extern unsigned long *ia32_gdt; extern unsigned long *ia32_gdt;
extern struct page *ia32_gate_page;
struct page * struct page *
ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int *type) 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_struct *vma, unsigned long address, int ...@@ -59,10 +60,25 @@ ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int
return pg; 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 = { static struct vm_operations_struct ia32_shared_page_vm_ops = {
.nopage = ia32_install_shared_page .nopage = ia32_install_shared_page
}; };
static struct vm_operations_struct ia32_gate_page_vm_ops = {
.nopage = ia32_install_gate_page
};
void void
ia64_elf32_init (struct pt_regs *regs) ia64_elf32_init (struct pt_regs *regs)
{ {
...@@ -89,6 +105,29 @@ ia64_elf32_init (struct pt_regs *regs) ...@@ -89,6 +105,29 @@ ia64_elf32_init (struct pt_regs *regs)
up_write(&current->mm->mmap_sem); up_write(&current->mm->mmap_sem);
} }
/*
* 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 * Install LDT as anonymous memory. This gives us all-zero segment descriptors
* until a task modifies them via modify_ldt(). * until a task modifies them via modify_ldt().
......
...@@ -853,13 +853,18 @@ setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs ...@@ -853,13 +853,18 @@ setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs
unsigned int restorer = IA32_SA_RESTORER(ka); unsigned int restorer = IA32_SA_RESTORER(ka);
err |= __put_user(restorer, &frame->pretcode); err |= __put_user(restorer, &frame->pretcode);
} else { } else {
err |= __put_user((long)frame->retcode, &frame->pretcode); /* Pointing to restorer in ia32 gate page */
/* This is popl %eax ; movl $,%eax ; int $0x80 */ 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(0xb858, (short *)(frame->retcode+0));
err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); err |= __put_user(__IA32_NR_sigreturn, (int *)(frame->retcode+2));
err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4));
err |= __put_user(0x80cd, (short *)(frame->retcode+6)); err |= __put_user(0x80cd, (short *)(frame->retcode+6));
}
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
...@@ -922,12 +927,18 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -922,12 +927,18 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info,
unsigned int restorer = IA32_SA_RESTORER(ka); unsigned int restorer = IA32_SA_RESTORER(ka);
err |= __put_user(restorer, &frame->pretcode); err |= __put_user(restorer, &frame->pretcode);
} else { } else {
err |= __put_user((long)frame->retcode, &frame->pretcode); /* Pointing to rt_restorer in ia32 gate page */
/* This is movl $,%eax ; int $0x80 */ 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(0xb8, (char *)(frame->retcode+0));
err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1));
err |= __put_user(0x80cd, (short *)(frame->retcode+5)); err |= __put_user(0x80cd, (short *)(frame->retcode+5));
}
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
......
...@@ -33,6 +33,7 @@ struct exec_domain ia32_exec_domain; ...@@ -33,6 +33,7 @@ struct exec_domain ia32_exec_domain;
struct page *ia32_shared_page[NR_CPUS]; struct page *ia32_shared_page[NR_CPUS];
unsigned long *ia32_boot_gdt; unsigned long *ia32_boot_gdt;
unsigned long *cpu_gdt_table[NR_CPUS]; unsigned long *cpu_gdt_table[NR_CPUS];
struct page *ia32_gate_page;
static unsigned long static unsigned long
load_desc (u16 selector) load_desc (u16 selector)
...@@ -158,7 +159,7 @@ ia32_gdt_init (void) ...@@ -158,7 +159,7 @@ ia32_gdt_init (void)
/* /*
* Setup IA32 GDT and TSS * Setup IA32 GDT and TSS
*/ */
void static void
ia32_boot_gdt_init (void) ia32_boot_gdt_init (void)
{ {
unsigned long ldt_size; unsigned long ldt_size;
...@@ -172,12 +173,12 @@ ia32_boot_gdt_init (void) ...@@ -172,12 +173,12 @@ ia32_boot_gdt_init (void)
/* CS descriptor in IA-32 (scrambled) format */ /* CS descriptor in IA-32 (scrambled) format */
ia32_boot_gdt[__USER_CS >> 3] 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); 0xb, 1, 3, 1, 1, 1, 1);
/* DS descriptor in IA-32 (scrambled) format */ /* DS descriptor in IA-32 (scrambled) format */
ia32_boot_gdt[__USER_DS >> 3] 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); 0x3, 1, 3, 1, 1, 1, 1);
ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
...@@ -187,6 +188,27 @@ ia32_boot_gdt_init (void) ...@@ -187,6 +188,27 @@ ia32_boot_gdt_init (void)
0x2, 0, 3, 1, 1, 1, 0); 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 * Handle bad IA32 interrupt via syscall
*/ */
......
...@@ -168,6 +168,9 @@ struct ia32_user_fxsr_struct { ...@@ -168,6 +168,9 @@ struct ia32_user_fxsr_struct {
#define IA32_SA_HANDLER(ka) ((unsigned long) (ka)->sa.sa_handler & 0xffffffff) #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_SA_RESTORER(ka) ((unsigned long) (ka)->sa.sa_handler >> 32)
#define __IA32_NR_sigreturn 119
#define __IA32_NR_rt_sigreturn 173
struct sigaction32 { struct sigaction32 {
unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */
unsigned int sa_flags; unsigned int sa_flags;
...@@ -324,14 +327,16 @@ struct old_linux32_dirent { ...@@ -324,14 +327,16 @@ struct old_linux32_dirent {
#define IA32_PAGE_OFFSET 0xc0000000 #define IA32_PAGE_OFFSET 0xc0000000
#define IA32_STACK_TOP IA32_PAGE_OFFSET #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 * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can
* access them. * access them.
*/ */
#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET) #define IA32_GDT_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE)
#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) #define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE)
#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) #define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 3*PAGE_SIZE)
#define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE #define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE
......
...@@ -587,6 +587,6 @@ mem_init (void) ...@@ -587,6 +587,6 @@ mem_init (void)
setup_gate(); setup_gate();
#ifdef CONFIG_IA32_SUPPORT #ifdef CONFIG_IA32_SUPPORT
ia32_boot_gdt_init(); ia32_mem_init();
#endif #endif
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# ifdef CONFIG_IA32_SUPPORT # ifdef CONFIG_IA32_SUPPORT
extern void ia32_cpu_init (void); 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 void ia32_gdt_init (void);
extern int ia32_exception (struct pt_regs *regs, unsigned long isr); extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); extern int ia32_intercept (struct pt_regs *regs, unsigned long isr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment