Skip to content

Commit ab09e95

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
x86/kprobes: Convert to text-patching.h
Convert kprobes to the new text-poke naming. Tested-by: Alexei Starovoitov <[email protected]> Tested-by: Steven Rostedt (VMware) <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Masami Hiramatsu <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 38ebd8d commit ab09e95

File tree

4 files changed

+37
-41
lines changed

4 files changed

+37
-41
lines changed

arch/x86/include/asm/kprobes.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111

1212
#include <asm-generic/kprobes.h>
1313

14-
#define BREAKPOINT_INSTRUCTION 0xcc
15-
1614
#ifdef CONFIG_KPROBES
1715
#include <linux/types.h>
1816
#include <linux/ptrace.h>
1917
#include <linux/percpu.h>
18+
#include <asm/text-patching.h>
2019
#include <asm/insn.h>
2120

2221
#define __ARCH_WANT_KPROBES_INSN_SLOT
@@ -25,10 +24,7 @@ struct pt_regs;
2524
struct kprobe;
2625

2726
typedef u8 kprobe_opcode_t;
28-
#define RELATIVEJUMP_OPCODE 0xe9
29-
#define RELATIVEJUMP_SIZE 5
30-
#define RELATIVECALL_OPCODE 0xe8
31-
#define RELATIVE_ADDR_SIZE 4
27+
3228
#define MAX_STACK_SIZE 64
3329
#define CUR_STACK_SIZE(ADDR) \
3430
(current_top_of_stack() - (unsigned long)(ADDR))
@@ -43,11 +39,11 @@ extern __visible kprobe_opcode_t optprobe_template_entry[];
4339
extern __visible kprobe_opcode_t optprobe_template_val[];
4440
extern __visible kprobe_opcode_t optprobe_template_call[];
4541
extern __visible kprobe_opcode_t optprobe_template_end[];
46-
#define MAX_OPTIMIZED_LENGTH (MAX_INSN_SIZE + RELATIVE_ADDR_SIZE)
42+
#define MAX_OPTIMIZED_LENGTH (MAX_INSN_SIZE + DISP32_SIZE)
4743
#define MAX_OPTINSN_SIZE \
4844
(((unsigned long)optprobe_template_end - \
4945
(unsigned long)optprobe_template_entry) + \
50-
MAX_OPTIMIZED_LENGTH + RELATIVEJUMP_SIZE)
46+
MAX_OPTIMIZED_LENGTH + JMP32_INSN_SIZE)
5147

5248
extern const int kretprobe_blacklist_size;
5349

@@ -73,7 +69,7 @@ struct arch_specific_insn {
7369

7470
struct arch_optimized_insn {
7571
/* copy of the original instructions */
76-
kprobe_opcode_t copied_insn[RELATIVE_ADDR_SIZE];
72+
kprobe_opcode_t copied_insn[DISP32_SIZE];
7773
/* detour code buffer */
7874
kprobe_opcode_t *insn;
7975
/* the size of instructions copied to detour code buffer */

arch/x86/include/asm/text-patching.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ extern void text_poke_finish(void);
6161
#define JMP8_INSN_SIZE 2
6262
#define JMP8_INSN_OPCODE 0xEB
6363

64+
#define DISP32_SIZE 4
65+
6466
static inline int text_opcode_size(u8 opcode)
6567
{
6668
int size = 0;

arch/x86/kernel/kprobes/core.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,14 @@ __synthesize_relative_insn(void *dest, void *from, void *to, u8 op)
119119
/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
120120
void synthesize_reljump(void *dest, void *from, void *to)
121121
{
122-
__synthesize_relative_insn(dest, from, to, RELATIVEJUMP_OPCODE);
122+
__synthesize_relative_insn(dest, from, to, JMP32_INSN_OPCODE);
123123
}
124124
NOKPROBE_SYMBOL(synthesize_reljump);
125125

126126
/* Insert a call instruction at address 'from', which calls address 'to'.*/
127127
void synthesize_relcall(void *dest, void *from, void *to)
128128
{
129-
__synthesize_relative_insn(dest, from, to, RELATIVECALL_OPCODE);
129+
__synthesize_relative_insn(dest, from, to, CALL_INSN_OPCODE);
130130
}
131131
NOKPROBE_SYMBOL(synthesize_relcall);
132132

@@ -301,7 +301,7 @@ static int can_probe(unsigned long paddr)
301301
* Another debugging subsystem might insert this breakpoint.
302302
* In that case, we can't recover it.
303303
*/
304-
if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
304+
if (insn.opcode.bytes[0] == INT3_INSN_OPCODE)
305305
return 0;
306306
addr += insn.length;
307307
}
@@ -356,7 +356,7 @@ int __copy_instruction(u8 *dest, u8 *src, u8 *real, struct insn *insn)
356356
return 0;
357357

358358
/* Another subsystem puts a breakpoint, failed to recover */
359-
if (insn->opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
359+
if (insn->opcode.bytes[0] == INT3_INSN_OPCODE)
360360
return 0;
361361

362362
/* We should not singlestep on the exception masking instructions */
@@ -400,14 +400,14 @@ static int prepare_boost(kprobe_opcode_t *buf, struct kprobe *p,
400400
int len = insn->length;
401401

402402
if (can_boost(insn, p->addr) &&
403-
MAX_INSN_SIZE - len >= RELATIVEJUMP_SIZE) {
403+
MAX_INSN_SIZE - len >= JMP32_INSN_SIZE) {
404404
/*
405405
* These instructions can be executed directly if it
406406
* jumps back to correct address.
407407
*/
408408
synthesize_reljump(buf + len, p->ainsn.insn + len,
409409
p->addr + insn->length);
410-
len += RELATIVEJUMP_SIZE;
410+
len += JMP32_INSN_SIZE;
411411
p->ainsn.boostable = true;
412412
} else {
413413
p->ainsn.boostable = false;
@@ -501,7 +501,7 @@ int arch_prepare_kprobe(struct kprobe *p)
501501

502502
void arch_arm_kprobe(struct kprobe *p)
503503
{
504-
text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
504+
text_poke(p->addr, ((unsigned char []){INT3_INSN_OPCODE}), 1);
505505
}
506506

507507
void arch_disarm_kprobe(struct kprobe *p)
@@ -609,7 +609,7 @@ static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
609609
regs->flags |= X86_EFLAGS_TF;
610610
regs->flags &= ~X86_EFLAGS_IF;
611611
/* single step inline if the instruction is an int3 */
612-
if (p->opcode == BREAKPOINT_INSTRUCTION)
612+
if (p->opcode == INT3_INSN_OPCODE)
613613
regs->ip = (unsigned long)p->addr;
614614
else
615615
regs->ip = (unsigned long)p->ainsn.insn;
@@ -695,7 +695,7 @@ int kprobe_int3_handler(struct pt_regs *regs)
695695
reset_current_kprobe();
696696
return 1;
697697
}
698-
} else if (*addr != BREAKPOINT_INSTRUCTION) {
698+
} else if (*addr != INT3_INSN_OPCODE) {
699699
/*
700700
* The breakpoint instruction was removed right
701701
* after we hit it. Another cpu has removed

arch/x86/kernel/kprobes/opt.c

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
3838
long offs;
3939
int i;
4040

41-
for (i = 0; i < RELATIVEJUMP_SIZE; i++) {
41+
for (i = 0; i < JMP32_INSN_SIZE; i++) {
4242
kp = get_kprobe((void *)addr - i);
4343
/* This function only handles jump-optimized kprobe */
4444
if (kp && kprobe_optimized(kp)) {
@@ -62,10 +62,10 @@ unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
6262

6363
if (addr == (unsigned long)kp->addr) {
6464
buf[0] = kp->opcode;
65-
memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
65+
memcpy(buf + 1, op->optinsn.copied_insn, DISP32_SIZE);
6666
} else {
6767
offs = addr - (unsigned long)kp->addr - 1;
68-
memcpy(buf, op->optinsn.copied_insn + offs, RELATIVE_ADDR_SIZE - offs);
68+
memcpy(buf, op->optinsn.copied_insn + offs, DISP32_SIZE - offs);
6969
}
7070

7171
return (unsigned long)buf;
@@ -141,8 +141,6 @@ STACK_FRAME_NON_STANDARD(optprobe_template_func);
141141
#define TMPL_END_IDX \
142142
((long)optprobe_template_end - (long)optprobe_template_entry)
143143

144-
#define INT3_SIZE sizeof(kprobe_opcode_t)
145-
146144
/* Optimized kprobe call back function: called from optinsn */
147145
static void
148146
optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
@@ -162,7 +160,7 @@ optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
162160
regs->cs |= get_kernel_rpl();
163161
regs->gs = 0;
164162
#endif
165-
regs->ip = (unsigned long)op->kp.addr + INT3_SIZE;
163+
regs->ip = (unsigned long)op->kp.addr + INT3_INSN_SIZE;
166164
regs->orig_ax = ~0UL;
167165

168166
__this_cpu_write(current_kprobe, &op->kp);
@@ -179,7 +177,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real)
179177
struct insn insn;
180178
int len = 0, ret;
181179

182-
while (len < RELATIVEJUMP_SIZE) {
180+
while (len < JMP32_INSN_SIZE) {
183181
ret = __copy_instruction(dest + len, src + len, real + len, &insn);
184182
if (!ret || !can_boost(&insn, src + len))
185183
return -EINVAL;
@@ -271,7 +269,7 @@ static int can_optimize(unsigned long paddr)
271269
return 0;
272270

273271
/* Check there is enough space for a relative jump. */
274-
if (size - offset < RELATIVEJUMP_SIZE)
272+
if (size - offset < JMP32_INSN_SIZE)
275273
return 0;
276274

277275
/* Decode instructions */
@@ -290,15 +288,15 @@ static int can_optimize(unsigned long paddr)
290288
kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
291289
insn_get_length(&insn);
292290
/* Another subsystem puts a breakpoint */
293-
if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
291+
if (insn.opcode.bytes[0] == INT3_INSN_OPCODE)
294292
return 0;
295293
/* Recover address */
296294
insn.kaddr = (void *)addr;
297295
insn.next_byte = (void *)(addr + insn.length);
298296
/* Check any instructions don't jump into target */
299297
if (insn_is_indirect_jump(&insn) ||
300-
insn_jump_into_range(&insn, paddr + INT3_SIZE,
301-
RELATIVE_ADDR_SIZE))
298+
insn_jump_into_range(&insn, paddr + INT3_INSN_SIZE,
299+
DISP32_SIZE))
302300
return 0;
303301
addr += insn.length;
304302
}
@@ -374,7 +372,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
374372
* Verify if the address gap is in 2GB range, because this uses
375373
* a relative jump.
376374
*/
377-
rel = (long)slot - (long)op->kp.addr + RELATIVEJUMP_SIZE;
375+
rel = (long)slot - (long)op->kp.addr + JMP32_INSN_SIZE;
378376
if (abs(rel) > 0x7fffffff) {
379377
ret = -ERANGE;
380378
goto err;
@@ -401,7 +399,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
401399
/* Set returning jmp instruction at the tail of out-of-line buffer */
402400
synthesize_reljump(buf + len, slot + len,
403401
(u8 *)op->kp.addr + op->optinsn.size);
404-
len += RELATIVEJUMP_SIZE;
402+
len += JMP32_INSN_SIZE;
405403

406404
/* We have to use text_poke() for instruction buffer because it is RO */
407405
text_poke(slot, buf, len);
@@ -422,22 +420,22 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
422420
void arch_optimize_kprobes(struct list_head *oplist)
423421
{
424422
struct optimized_kprobe *op, *tmp;
425-
u8 insn_buff[RELATIVEJUMP_SIZE];
423+
u8 insn_buff[JMP32_INSN_SIZE];
426424

427425
list_for_each_entry_safe(op, tmp, oplist, list) {
428426
s32 rel = (s32)((long)op->optinsn.insn -
429-
((long)op->kp.addr + RELATIVEJUMP_SIZE));
427+
((long)op->kp.addr + JMP32_INSN_SIZE));
430428

431429
WARN_ON(kprobe_disabled(&op->kp));
432430

433431
/* Backup instructions which will be replaced by jump address */
434-
memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE,
435-
RELATIVE_ADDR_SIZE);
432+
memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_INSN_SIZE,
433+
DISP32_SIZE);
436434

437-
insn_buff[0] = RELATIVEJUMP_OPCODE;
435+
insn_buff[0] = JMP32_INSN_OPCODE;
438436
*(s32 *)(&insn_buff[1]) = rel;
439437

440-
text_poke_bp(op->kp.addr, insn_buff, RELATIVEJUMP_SIZE, NULL);
438+
text_poke_bp(op->kp.addr, insn_buff, JMP32_INSN_SIZE, NULL);
441439

442440
list_del_init(&op->list);
443441
}
@@ -446,13 +444,13 @@ void arch_optimize_kprobes(struct list_head *oplist)
446444
/* Replace a relative jump with a breakpoint (int3). */
447445
void arch_unoptimize_kprobe(struct optimized_kprobe *op)
448446
{
449-
u8 insn_buff[RELATIVEJUMP_SIZE];
447+
u8 insn_buff[JMP32_INSN_SIZE];
450448

451449
/* Set int3 to first byte for kprobes */
452-
insn_buff[0] = BREAKPOINT_INSTRUCTION;
453-
memcpy(insn_buff + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
450+
insn_buff[0] = INT3_INSN_OPCODE;
451+
memcpy(insn_buff + 1, op->optinsn.copied_insn, DISP32_SIZE);
454452

455-
text_poke_bp(op->kp.addr, insn_buff, RELATIVEJUMP_SIZE,
453+
text_poke_bp(op->kp.addr, insn_buff, JMP32_INSN_SIZE,
456454
text_gen_insn(JMP32_INSN_OPCODE, op->kp.addr, op->optinsn.insn));
457455
}
458456

0 commit comments

Comments
 (0)