@@ -119,29 +119,29 @@ struct kretprobe_blackpoint kretprobe_blacklist[] = {
119
119
const int kretprobe_blacklist_size = ARRAY_SIZE (kretprobe_blacklist );
120
120
121
121
static nokprobe_inline void
122
- __synthesize_relative_insn (void * from , void * to , u8 op )
122
+ __synthesize_relative_insn (void * dest , void * from , void * to , u8 op )
123
123
{
124
124
struct __arch_relative_insn {
125
125
u8 op ;
126
126
s32 raddr ;
127
127
} __packed * insn ;
128
128
129
- insn = (struct __arch_relative_insn * )from ;
129
+ insn = (struct __arch_relative_insn * )dest ;
130
130
insn -> raddr = (s32 )((long )(to ) - ((long )(from ) + 5 ));
131
131
insn -> op = op ;
132
132
}
133
133
134
134
/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
135
- void synthesize_reljump (void * from , void * to )
135
+ void synthesize_reljump (void * dest , void * from , void * to )
136
136
{
137
- __synthesize_relative_insn (from , to , RELATIVEJUMP_OPCODE );
137
+ __synthesize_relative_insn (dest , from , to , RELATIVEJUMP_OPCODE );
138
138
}
139
139
NOKPROBE_SYMBOL (synthesize_reljump );
140
140
141
141
/* Insert a call instruction at address 'from', which calls address 'to'.*/
142
- void synthesize_relcall (void * from , void * to )
142
+ void synthesize_relcall (void * dest , void * from , void * to )
143
143
{
144
- __synthesize_relative_insn (from , to , RELATIVECALL_OPCODE );
144
+ __synthesize_relative_insn (dest , from , to , RELATIVECALL_OPCODE );
145
145
}
146
146
NOKPROBE_SYMBOL (synthesize_relcall );
147
147
@@ -346,10 +346,11 @@ static int is_IF_modifier(kprobe_opcode_t *insn)
346
346
/*
347
347
* Copy an instruction with recovering modified instruction by kprobes
348
348
* and adjust the displacement if the instruction uses the %rip-relative
349
- * addressing mode.
349
+ * addressing mode. Note that since @real will be the final place of copied
350
+ * instruction, displacement must be adjust by @real, not @dest.
350
351
* This returns the length of copied instruction, or 0 if it has an error.
351
352
*/
352
- int __copy_instruction (u8 * dest , u8 * src , struct insn * insn )
353
+ int __copy_instruction (u8 * dest , u8 * src , u8 * real , struct insn * insn )
353
354
{
354
355
kprobe_opcode_t buf [MAX_INSN_SIZE ];
355
356
unsigned long recovered_insn =
@@ -387,11 +388,11 @@ int __copy_instruction(u8 *dest, u8 *src, struct insn *insn)
387
388
* have given.
388
389
*/
389
390
newdisp = (u8 * ) src + (s64 ) insn -> displacement .value
390
- - (u8 * ) dest ;
391
+ - (u8 * ) real ;
391
392
if ((s64 ) (s32 ) newdisp != newdisp ) {
392
393
pr_err ("Kprobes error: new displacement does not fit into s32 (%llx)\n" , newdisp );
393
394
pr_err ("\tSrc: %p, Dest: %p, old disp: %x\n" ,
394
- src , dest , insn -> displacement .value );
395
+ src , real , insn -> displacement .value );
395
396
return 0 ;
396
397
}
397
398
disp = (u8 * ) dest + insn_offset_displacement (insn );
@@ -402,20 +403,38 @@ int __copy_instruction(u8 *dest, u8 *src, struct insn *insn)
402
403
}
403
404
404
405
/* Prepare reljump right after instruction to boost */
405
- static void prepare_boost (struct kprobe * p , struct insn * insn )
406
+ static int prepare_boost (kprobe_opcode_t * buf , struct kprobe * p ,
407
+ struct insn * insn )
406
408
{
409
+ int len = insn -> length ;
410
+
407
411
if (can_boost (insn , p -> addr ) &&
408
- MAX_INSN_SIZE - insn -> length >= RELATIVEJUMP_SIZE ) {
412
+ MAX_INSN_SIZE - len >= RELATIVEJUMP_SIZE ) {
409
413
/*
410
414
* These instructions can be executed directly if it
411
415
* jumps back to correct address.
412
416
*/
413
- synthesize_reljump (p -> ainsn .insn + insn -> length ,
417
+ synthesize_reljump (buf + len , p -> ainsn .insn + len ,
414
418
p -> addr + insn -> length );
419
+ len += RELATIVEJUMP_SIZE ;
415
420
p -> ainsn .boostable = true;
416
421
} else {
417
422
p -> ainsn .boostable = false;
418
423
}
424
+
425
+ return len ;
426
+ }
427
+
428
+ /* Make page to RO mode when allocate it */
429
+ void * alloc_insn_page (void )
430
+ {
431
+ void * page ;
432
+
433
+ page = module_alloc (PAGE_SIZE );
434
+ if (page )
435
+ set_memory_ro ((unsigned long )page & PAGE_MASK , 1 );
436
+
437
+ return page ;
419
438
}
420
439
421
440
/* Recover page to RW mode before releasing it */
@@ -429,28 +448,28 @@ void free_insn_page(void *page)
429
448
static int arch_copy_kprobe (struct kprobe * p )
430
449
{
431
450
struct insn insn ;
451
+ kprobe_opcode_t buf [MAX_INSN_SIZE ];
432
452
int len ;
433
453
434
- set_memory_rw ((unsigned long )p -> ainsn .insn & PAGE_MASK , 1 );
435
-
436
454
/* Copy an instruction with recovering if other optprobe modifies it.*/
437
- len = __copy_instruction (p -> ainsn . insn , p -> addr , & insn );
455
+ len = __copy_instruction (buf , p -> addr , p -> ainsn . insn , & insn );
438
456
if (!len )
439
457
return - EINVAL ;
440
458
441
459
/*
442
460
* __copy_instruction can modify the displacement of the instruction,
443
461
* but it doesn't affect boostable check.
444
462
*/
445
- prepare_boost (p , & insn );
446
-
447
- set_memory_ro ((unsigned long )p -> ainsn .insn & PAGE_MASK , 1 );
463
+ len = prepare_boost (buf , p , & insn );
448
464
449
465
/* Check whether the instruction modifies Interrupt Flag or not */
450
- p -> ainsn .if_modifier = is_IF_modifier (p -> ainsn . insn );
466
+ p -> ainsn .if_modifier = is_IF_modifier (buf );
451
467
452
468
/* Also, displacement change doesn't affect the first byte */
453
- p -> opcode = p -> ainsn .insn [0 ];
469
+ p -> opcode = buf [0 ];
470
+
471
+ /* OK, write back the instruction(s) into ROX insn buffer */
472
+ text_poke (p -> ainsn .insn , buf , len );
454
473
455
474
return 0 ;
456
475
}
0 commit comments