Commit 1f7ad57b authored by Prasanna S Panchamukhi's avatar Prasanna S Panchamukhi Committed by Linus Torvalds

[PATCH] Kprobes: prevent possible race conditions ia64 changes

This patch contains the ia64 architecture specific changes to prevent the
possible race conditions.
Signed-off-by: default avatarPrasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent bb144a85
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
/* /*
* void jprobe_break(void) * void jprobe_break(void)
*/ */
.section .kprobes.text, "ax"
ENTRY(jprobe_break) ENTRY(jprobe_break)
break.m 0x80300 break.m 0x80300
END(jprobe_break) END(jprobe_break)
......
...@@ -87,8 +87,10 @@ static enum instruction_type bundle_encoding[32][3] = { ...@@ -87,8 +87,10 @@ static enum instruction_type bundle_encoding[32][3] = {
* is IP relative instruction and update the kprobe * is IP relative instruction and update the kprobe
* inst flag accordingly * inst flag accordingly
*/ */
static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode, static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
unsigned long kprobe_inst, struct kprobe *p) uint major_opcode,
unsigned long kprobe_inst,
struct kprobe *p)
{ {
p->ainsn.inst_flag = 0; p->ainsn.inst_flag = 0;
p->ainsn.target_br_reg = 0; p->ainsn.target_br_reg = 0;
...@@ -126,8 +128,10 @@ static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode ...@@ -126,8 +128,10 @@ static void update_kprobe_inst_flag(uint template, uint slot, uint major_opcode
* Returns 0 if supported * Returns 0 if supported
* Returns -EINVAL if unsupported * Returns -EINVAL if unsupported
*/ */
static int unsupported_inst(uint template, uint slot, uint major_opcode, static int __kprobes unsupported_inst(uint template, uint slot,
unsigned long kprobe_inst, struct kprobe *p) uint major_opcode,
unsigned long kprobe_inst,
struct kprobe *p)
{ {
unsigned long addr = (unsigned long)p->addr; unsigned long addr = (unsigned long)p->addr;
...@@ -168,8 +172,9 @@ static int unsupported_inst(uint template, uint slot, uint major_opcode, ...@@ -168,8 +172,9 @@ static int unsupported_inst(uint template, uint slot, uint major_opcode,
* on which we are inserting kprobe is cmp instruction * on which we are inserting kprobe is cmp instruction
* with ctype as unc. * with ctype as unc.
*/ */
static uint is_cmp_ctype_unc_inst(uint template, uint slot, uint major_opcode, static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
unsigned long kprobe_inst) uint major_opcode,
unsigned long kprobe_inst)
{ {
cmp_inst_t cmp_inst; cmp_inst_t cmp_inst;
uint ctype_unc = 0; uint ctype_unc = 0;
...@@ -201,8 +206,10 @@ out: ...@@ -201,8 +206,10 @@ out:
* In this function we override the bundle with * In this function we override the bundle with
* the break instruction at the given slot. * the break instruction at the given slot.
*/ */
static void prepare_break_inst(uint template, uint slot, uint major_opcode, static void __kprobes prepare_break_inst(uint template, uint slot,
unsigned long kprobe_inst, struct kprobe *p) uint major_opcode,
unsigned long kprobe_inst,
struct kprobe *p)
{ {
unsigned long break_inst = BREAK_INST; unsigned long break_inst = BREAK_INST;
bundle_t *bundle = &p->ainsn.insn.bundle; bundle_t *bundle = &p->ainsn.insn.bundle;
...@@ -271,7 +278,8 @@ static inline int in_ivt_functions(unsigned long addr) ...@@ -271,7 +278,8 @@ static inline int in_ivt_functions(unsigned long addr)
&& addr < (unsigned long)__end_ivt_text); && addr < (unsigned long)__end_ivt_text);
} }
static int valid_kprobe_addr(int template, int slot, unsigned long addr) static int __kprobes valid_kprobe_addr(int template, int slot,
unsigned long addr)
{ {
if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) { if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
printk(KERN_WARNING "Attempting to insert unaligned kprobe " printk(KERN_WARNING "Attempting to insert unaligned kprobe "
...@@ -323,7 +331,7 @@ static void kretprobe_trampoline(void) ...@@ -323,7 +331,7 @@ static void kretprobe_trampoline(void)
* - cleanup by marking the instance as unused * - cleanup by marking the instance as unused
* - long jump back to the original return address * - long jump back to the original return address
*/ */
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 kretprobe_instance *ri = NULL;
struct hlist_head *head; struct hlist_head *head;
...@@ -381,7 +389,8 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -381,7 +389,8 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
return 1; return 1;
} }
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
struct pt_regs *regs)
{ {
struct kretprobe_instance *ri; struct kretprobe_instance *ri;
...@@ -399,7 +408,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) ...@@ -399,7 +408,7 @@ void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
} }
} }
int arch_prepare_kprobe(struct kprobe *p) int __kprobes arch_prepare_kprobe(struct kprobe *p)
{ {
unsigned long addr = (unsigned long) p->addr; unsigned long addr = (unsigned long) p->addr;
unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL); unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
...@@ -430,7 +439,7 @@ int arch_prepare_kprobe(struct kprobe *p) ...@@ -430,7 +439,7 @@ int arch_prepare_kprobe(struct kprobe *p)
return 0; return 0;
} }
void arch_arm_kprobe(struct kprobe *p) void __kprobes arch_arm_kprobe(struct kprobe *p)
{ {
unsigned long addr = (unsigned long)p->addr; unsigned long addr = (unsigned long)p->addr;
unsigned long arm_addr = addr & ~0xFULL; unsigned long arm_addr = addr & ~0xFULL;
...@@ -439,7 +448,7 @@ void arch_arm_kprobe(struct kprobe *p) ...@@ -439,7 +448,7 @@ void arch_arm_kprobe(struct kprobe *p)
flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
} }
void arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_disarm_kprobe(struct kprobe *p)
{ {
unsigned long addr = (unsigned long)p->addr; unsigned long addr = (unsigned long)p->addr;
unsigned long arm_addr = addr & ~0xFULL; unsigned long arm_addr = addr & ~0xFULL;
...@@ -449,7 +458,7 @@ void arch_disarm_kprobe(struct kprobe *p) ...@@ -449,7 +458,7 @@ void arch_disarm_kprobe(struct kprobe *p)
flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
} }
void arch_remove_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p)
{ {
} }
...@@ -461,7 +470,7 @@ void arch_remove_kprobe(struct kprobe *p) ...@@ -461,7 +470,7 @@ void arch_remove_kprobe(struct kprobe *p)
* to original stack address, handle the case where we need to fixup the * to original stack address, handle the case where we need to fixup the
* relative IP address and/or fixup branch register. * relative IP address and/or fixup branch register.
*/ */
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 bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL; unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
...@@ -528,7 +537,7 @@ turn_ss_off: ...@@ -528,7 +537,7 @@ turn_ss_off:
ia64_psr(regs)->ss = 0; ia64_psr(regs)->ss = 0;
} }
static void prepare_ss(struct kprobe *p, struct pt_regs *regs) static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
{ {
unsigned long bundle_addr = (unsigned long) &p->opcode.bundle; unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
unsigned long slot = (unsigned long)p->addr & 0xf; unsigned long slot = (unsigned long)p->addr & 0xf;
...@@ -545,7 +554,7 @@ static void prepare_ss(struct kprobe *p, struct pt_regs *regs) ...@@ -545,7 +554,7 @@ static void prepare_ss(struct kprobe *p, struct pt_regs *regs)
ia64_psr(regs)->ss = 1; ia64_psr(regs)->ss = 1;
} }
static int pre_kprobes_handler(struct die_args *args) static int __kprobes pre_kprobes_handler(struct die_args *args)
{ {
struct kprobe *p; struct kprobe *p;
int ret = 0; int ret = 0;
...@@ -616,7 +625,7 @@ no_kprobe: ...@@ -616,7 +625,7 @@ no_kprobe:
return ret; return ret;
} }
static int post_kprobes_handler(struct pt_regs *regs) static int __kprobes post_kprobes_handler(struct pt_regs *regs)
{ {
if (!kprobe_running()) if (!kprobe_running())
return 0; return 0;
...@@ -641,7 +650,7 @@ out: ...@@ -641,7 +650,7 @@ out:
return 1; return 1;
} }
static int kprobes_fault_handler(struct pt_regs *regs, int trapnr) static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr)
{ {
if (!kprobe_running()) if (!kprobe_running())
return 0; return 0;
...@@ -659,8 +668,8 @@ static int kprobes_fault_handler(struct pt_regs *regs, int trapnr) ...@@ -659,8 +668,8 @@ static int kprobes_fault_handler(struct pt_regs *regs, int trapnr)
return 0; return 0;
} }
int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
void *data) unsigned long val, void *data)
{ {
struct die_args *args = (struct die_args *)data; struct die_args *args = (struct die_args *)data;
switch(val) { switch(val) {
...@@ -681,7 +690,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, ...@@ -681,7 +690,7 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
return NOTIFY_DONE; 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); struct jprobe *jp = container_of(p, struct jprobe, kp);
unsigned long addr = ((struct fnptr *)(jp->entry))->ip; unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
...@@ -703,7 +712,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -703,7 +712,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
return 1; return 1;
} }
int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{ {
*regs = jprobe_saved_regs; *regs = jprobe_saved_regs;
return 1; return 1;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/vt_kern.h> /* For unblank_screen() */ #include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/module.h> /* for EXPORT_SYMBOL */ #include <linux/module.h> /* for EXPORT_SYMBOL */
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/kprobes.h>
#include <asm/fpswa.h> #include <asm/fpswa.h>
#include <asm/ia32.h> #include <asm/ia32.h>
...@@ -122,7 +123,7 @@ die_if_kernel (char *str, struct pt_regs *regs, long err) ...@@ -122,7 +123,7 @@ die_if_kernel (char *str, struct pt_regs *regs, long err)
} }
void void
ia64_bad_break (unsigned long break_num, struct pt_regs *regs) __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
{ {
siginfo_t siginfo; siginfo_t siginfo;
int sig, code; int sig, code;
...@@ -444,7 +445,7 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3, ...@@ -444,7 +445,7 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3,
return rv; return rv;
} }
void void __kprobes
ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
unsigned long iim, unsigned long itir, long arg5, long arg6, unsigned long iim, unsigned long itir, long arg5, long arg6,
long arg7, struct pt_regs regs) long arg7, struct pt_regs regs)
......
...@@ -48,6 +48,7 @@ SECTIONS ...@@ -48,6 +48,7 @@ SECTIONS
*(.text) *(.text)
SCHED_TEXT SCHED_TEXT
LOCK_TEXT LOCK_TEXT
KPROBES_TEXT
*(.gnu.linkonce.t*) *(.gnu.linkonce.t*)
} }
.text2 : AT(ADDR(.text2) - LOAD_OFFSET) .text2 : AT(ADDR(.text2) - LOAD_OFFSET)
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
* *
* Note: "in0" and "in1" are preserved for debugging purposes. * Note: "in0" and "in1" are preserved for debugging purposes.
*/ */
.section .kprobes.text,"ax"
GLOBAL_ENTRY(flush_icache_range) GLOBAL_ENTRY(flush_icache_range)
.prologue .prologue
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kprobes.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -76,7 +77,7 @@ mapped_kernel_page_is_present (unsigned long address) ...@@ -76,7 +77,7 @@ mapped_kernel_page_is_present (unsigned long address)
return pte_present(pte); return pte_present(pte);
} }
void void __kprobes
ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs)
{ {
int signal = SIGSEGV, code = SEGV_MAPERR; int signal = SIGSEGV, code = SEGV_MAPERR;
......
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