Skip to content

Commit

Permalink
[PATCH] kprobes: prevent possible race conditions i386 changes
Browse files Browse the repository at this point in the history
This patch contains the i386 architecture specific changes to prevent the
possible race conditions.

Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Prasanna S Panchamukhi authored and Linus Torvalds committed Sep 7, 2005
1 parent d0aaff9 commit 3d97ae5
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 25 deletions.
13 changes: 8 additions & 5 deletions arch/i386/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ label: \
pushl $__KERNEL_CS; \
pushl $sysenter_past_esp

ENTRY(debug)
KPROBE_ENTRY(debug)
cmpl $sysenter_entry,(%esp)
jne debug_stack_correct
FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
Expand All @@ -518,7 +518,7 @@ debug_stack_correct:
movl %esp,%eax # pt_regs pointer
call do_debug
jmp ret_from_exception

.previous .text
/*
* NMI is doubly nasty. It can happen _while_ we're handling
* a debug fault, and the debug fault hasn't yet been able to
Expand Down Expand Up @@ -591,13 +591,14 @@ nmi_16bit_stack:
.long 1b,iret_exc
.previous

ENTRY(int3)
KPROBE_ENTRY(int3)
pushl $-1 # mark this as an int
SAVE_ALL
xorl %edx,%edx # zero error code
movl %esp,%eax # pt_regs pointer
call do_int3
jmp ret_from_exception
.previous .text

ENTRY(overflow)
pushl $0
Expand Down Expand Up @@ -631,17 +632,19 @@ ENTRY(stack_segment)
pushl $do_stack_segment
jmp error_code

ENTRY(general_protection)
KPROBE_ENTRY(general_protection)
pushl $do_general_protection
jmp error_code
.previous .text

ENTRY(alignment_check)
pushl $do_alignment_check
jmp error_code

ENTRY(page_fault)
KPROBE_ENTRY(page_fault)
pushl $do_page_fault
jmp error_code
.previous .text

#ifdef CONFIG_X86_MCE
ENTRY(machine_check)
Expand Down
29 changes: 15 additions & 14 deletions arch/i386/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,32 +62,32 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode)
return 0;
}

int arch_prepare_kprobe(struct kprobe *p)
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
return 0;
}

void arch_copy_kprobe(struct kprobe *p)
void __kprobes arch_copy_kprobe(struct kprobe *p)
{
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
}

void arch_arm_kprobe(struct kprobe *p)
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}

void arch_disarm_kprobe(struct kprobe *p)
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
*p->addr = p->opcode;
flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
}

void arch_remove_kprobe(struct kprobe *p)
void __kprobes arch_remove_kprobe(struct kprobe *p)
{
}

Expand Down Expand Up @@ -127,7 +127,8 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
regs->eip = (unsigned long)&p->ainsn.insn;
}

void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)&regs->esp;
struct kretprobe_instance *ri;
Expand All @@ -150,7 +151,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
* remain disabled thorough out this function.
*/
static int kprobe_handler(struct pt_regs *regs)
static int __kprobes kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
int ret = 0;
Expand Down Expand Up @@ -259,7 +260,7 @@ static int kprobe_handler(struct pt_regs *regs)
/*
* Called when we hit the probe point at kretprobe_trampoline
*/
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
struct hlist_head *head;
Expand Down Expand Up @@ -338,7 +339,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
* that is atop the stack is the address following the copied instruction.
* We need to make it the address following the original instruction.
*/
static void resume_execution(struct kprobe *p, struct pt_regs *regs)
static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
unsigned long *tos = (unsigned long *)&regs->esp;
unsigned long next_eip = 0;
Expand Down Expand Up @@ -444,8 +445,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
/*
* Wrapper routine to for handling exceptions.
*/
int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
void *data)
int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
switch (val) {
Expand Down Expand Up @@ -473,7 +474,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
return NOTIFY_DONE;
}

int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
unsigned long addr;
Expand All @@ -495,7 +496,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
return 1;
}

void jprobe_return(void)
void __kprobes jprobe_return(void)
{
preempt_enable_no_resched();
asm volatile (" xchgl %%ebx,%%esp \n"
Expand All @@ -506,7 +507,7 @@ void jprobe_return(void)
(jprobe_saved_esp):"memory");
}

int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
u8 *addr = (u8 *) (regs->eip - 1);
unsigned long stack_addr = (unsigned long)jprobe_saved_esp;
Expand Down
12 changes: 7 additions & 5 deletions arch/i386/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,9 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
die(str, regs, err);
}

static void do_trap(int trapnr, int signr, char *str, int vm86,
struct pt_regs * regs, long error_code, siginfo_t *info)
static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
struct pt_regs * regs, long error_code,
siginfo_t *info)
{
struct task_struct *tsk = current;
tsk->thread.error_code = error_code;
Expand Down Expand Up @@ -460,7 +461,8 @@ DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)

fastcall void do_general_protection(struct pt_regs * regs, long error_code)
fastcall void __kprobes do_general_protection(struct pt_regs * regs,
long error_code)
{
int cpu = get_cpu();
struct tss_struct *tss = &per_cpu(init_tss, cpu);
Expand Down Expand Up @@ -676,7 +678,7 @@ void unset_nmi_callback(void)
EXPORT_SYMBOL_GPL(unset_nmi_callback);

#ifdef CONFIG_KPROBES
fastcall void do_int3(struct pt_regs *regs, long error_code)
fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
{
if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
== NOTIFY_STOP)
Expand Down Expand Up @@ -710,7 +712,7 @@ fastcall void do_int3(struct pt_regs *regs, long error_code)
* find every occurrence of the TF bit that could be saved away even
* by user code)
*/
fastcall void do_debug(struct pt_regs * regs, long error_code)
fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
{
unsigned int condition;
struct task_struct *tsk = current;
Expand Down
1 change: 1 addition & 0 deletions arch/i386/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ SECTIONS
*(.text)
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
} = 0x9090
Expand Down
4 changes: 3 additions & 1 deletion arch/i386/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/kprobes.h>

#include <asm/system.h>
#include <asm/uaccess.h>
Expand Down Expand Up @@ -223,7 +224,8 @@ fastcall void do_invalid_op(struct pt_regs *, unsigned long);
* bit 1 == 0 means read, 1 means write
* bit 2 == 0 means kernel, 1 means user-mode
*/
fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
fastcall void __kprobes do_page_fault(struct pt_regs *regs,
unsigned long error_code)
{
struct task_struct *tsk;
struct mm_struct *mm;
Expand Down

0 comments on commit 3d97ae5

Please sign in to comment.