-
-
-/*
- * lazy-check for CS validity on exec-shield binaries:
- *
- * the original non-exec stack patch was written by
- * Solar Designer <solar at openwall.com>. Thanks!
- */
-static int
-check_lazy_exec_limit(int cpu, struct pt_regs *regs, long error_code)
-{
- struct desc_struct *desc1, *desc2;
- struct vm_area_struct *vma;
- unsigned long limit;
-
- if (current->mm == NULL)
- return 0;
-
- limit = -1UL;
- if (current->mm->context.exec_limit != -1UL) {
- limit = PAGE_SIZE;
- spin_lock(¤t->mm->page_table_lock);
- for (vma = current->mm->mmap; vma; vma = vma->vm_next)
- if ((vma->vm_flags & VM_EXEC) && (vma->vm_end > limit))
- limit = vma->vm_end;
- spin_unlock(¤t->mm->page_table_lock);
- if (limit >= TASK_SIZE)
- limit = -1UL;
- current->mm->context.exec_limit = limit;
- }
- set_user_cs(¤t->mm->context.user_cs, limit);
-
- desc1 = ¤t->mm->context.user_cs;
- desc2 = get_cpu_gdt_table(cpu) + GDT_ENTRY_DEFAULT_USER_CS;
-
- if (desc1->a != desc2->a || desc1->b != desc2->b) {
- /*
- * The CS was not in sync - reload it and retry the
- * instruction. If the instruction still faults then
- * we won't hit this branch next time around.
- */
- if (print_fatal_signals >= 2) {
- printk("#GPF fixup (%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->eip, smp_processor_id());
- printk(" exec_limit: %08lx, user_cs: %08lx/%08lx, CPU_cs: %08lx/%08lx.\n", current->mm->context.exec_limit, desc1->a, desc1->b, desc2->a, desc2->b);
- }
- load_user_cs_desc(cpu, current->mm);
- return 1;
- }
-
- return 0;
-}
-
-/*
- * The fixup code for errors in iret jumps to here (iret_exc). It loses
- * the original trap number and error code. The bogus trap 32 and error
- * code 0 are what the vanilla kernel delivers via:
- * DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
- *
- * In case of a general protection fault in the iret instruction, we
- * need to check for a lazy CS update for exec-shield.
- */
-fastcall void do_iret_error(struct pt_regs *regs, long error_code)
-{
- int ok = check_lazy_exec_limit(get_cpu(), regs, error_code);
- put_cpu();
- if (!ok && notify_die(DIE_TRAP, "iret exception", regs,
- error_code, 32, SIGSEGV) != NOTIFY_STOP) {
- siginfo_t info;
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = ILL_BADSTK;
- info.si_addr = 0;
- do_trap(32, SIGSEGV, "iret exception", 0, regs, error_code,
- &info);
- }
-}