Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

powerpc: Reject probes on instructions that can't be single stepped

Per the ISA, a Trace interrupt is not generated for:
- [h|u]rfi[d]
- rfscv
- sc, scv, and Trap instructions that trap
- Power-Saving Mode instructions
- other instructions that cause interrupts (other than Trace interrupts)
- the first instructions of any interrupt handler (applies to Branch and Single Step tracing;
CIABR matches may still occur)
- instructions that are emulated by software

Add a helper to check for instructions belonging to the first four
categories above and to reject kprobes, uprobes and xmon breakpoints on
such instructions. We reject probing on instructions belonging to these
categories across all ISA versions and across both BookS and BookE.

For trap instructions, we can't know in advance if they can cause a
trap, and there is no good reason to allow probing on those. Also,
uprobes already refuses to probe trap instructions and kprobes does not
allow probes on trap instructions used for kernel warnings and bugs. As
such, stop allowing any type of probes/breakpoints on trap instruction
across uprobes, kprobes and xmon.

For some of the fp/altivec instructions that can generate an interrupt
and which we emulate in the kernel (altivec assist, for example), we
check and turn off single stepping in emulate_single_step().

Instructions generating a DSI are restarted and single stepping normally
completes once the instruction is completed.

In uprobes, if a single stepped instruction results in a non-fatal
signal to be delivered to the task, such signals are "delayed" until
after the instruction completes. For fatal signals, single stepping is
cancelled and the instruction restarted in-place so that core dump
captures proper addresses.

In kprobes, we do not allow probes on instructions having an extable
entry and we also do not allow probing interrupt vectors.

Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/f56ee979d50b8711fae350fc97870f3ca34acd75.1648648712.git.naveen.n.rao@linux.vnet.ibm.com

authored by

Naveen N. Rao and committed by
Michael Ellerman
54cdacd7 f31c6183

+66 -8
+18
arch/powerpc/include/asm/ppc-opcode.h
··· 130 130 #define OP_PREFIX 1 131 131 #define OP_TRAP_64 2 132 132 #define OP_TRAP 3 133 + #define OP_SC 17 134 + #define OP_19 19 133 135 #define OP_31 31 134 136 #define OP_LWZ 32 135 137 #define OP_LWZU 33 ··· 161 159 #define OP_LD 58 162 160 #define OP_STD 62 163 161 162 + #define OP_19_XOP_RFID 18 163 + #define OP_19_XOP_RFMCI 38 164 + #define OP_19_XOP_RFDI 39 165 + #define OP_19_XOP_RFI 50 166 + #define OP_19_XOP_RFCI 51 167 + #define OP_19_XOP_RFSCV 82 168 + #define OP_19_XOP_HRFID 274 169 + #define OP_19_XOP_URFID 306 170 + #define OP_19_XOP_STOP 370 171 + #define OP_19_XOP_DOZE 402 172 + #define OP_19_XOP_NAP 434 173 + #define OP_19_XOP_SLEEP 466 174 + #define OP_19_XOP_RVWINKLE 498 175 + 164 176 #define OP_31_XOP_TRAP 4 165 177 #define OP_31_XOP_LDX 21 166 178 #define OP_31_XOP_LWZX 23 ··· 195 179 #define OP_31_XOP_LHZUX 311 196 180 #define OP_31_XOP_MSGSNDP 142 197 181 #define OP_31_XOP_MSGCLRP 174 182 + #define OP_31_XOP_MTMSR 146 183 + #define OP_31_XOP_MTMSRD 178 198 184 #define OP_31_XOP_TLBIE 306 199 185 #define OP_31_XOP_MFSPR 339 200 186 #define OP_31_XOP_LWAX 341
+36
arch/powerpc/include/asm/probes.h
··· 8 8 * Copyright IBM Corporation, 2012 9 9 */ 10 10 #include <linux/types.h> 11 + #include <asm/disassemble.h> 11 12 12 13 typedef u32 ppc_opcode_t; 13 14 #define BREAKPOINT_INSTRUCTION 0x7fe00008 /* trap */ ··· 31 30 #else 32 31 #define MSR_SINGLESTEP (MSR_SE) 33 32 #endif 33 + 34 + static inline bool can_single_step(u32 inst) 35 + { 36 + switch (get_op(inst)) { 37 + case OP_TRAP_64: return false; 38 + case OP_TRAP: return false; 39 + case OP_SC: return false; 40 + case OP_19: 41 + switch (get_xop(inst)) { 42 + case OP_19_XOP_RFID: return false; 43 + case OP_19_XOP_RFMCI: return false; 44 + case OP_19_XOP_RFDI: return false; 45 + case OP_19_XOP_RFI: return false; 46 + case OP_19_XOP_RFCI: return false; 47 + case OP_19_XOP_RFSCV: return false; 48 + case OP_19_XOP_HRFID: return false; 49 + case OP_19_XOP_URFID: return false; 50 + case OP_19_XOP_STOP: return false; 51 + case OP_19_XOP_DOZE: return false; 52 + case OP_19_XOP_NAP: return false; 53 + case OP_19_XOP_SLEEP: return false; 54 + case OP_19_XOP_RVWINKLE: return false; 55 + } 56 + break; 57 + case OP_31: 58 + switch (get_xop(inst)) { 59 + case OP_31_XOP_TRAP: return false; 60 + case OP_31_XOP_TRAP_64: return false; 61 + case OP_31_XOP_MTMSR: return false; 62 + case OP_31_XOP_MTMSRD: return false; 63 + } 64 + break; 65 + } 66 + return true; 67 + } 34 68 35 69 /* Enable single stepping for the current task */ 36 70 static inline void enable_single_step(struct pt_regs *regs)
+2 -2
arch/powerpc/kernel/kprobes.c
··· 150 150 if ((unsigned long)p->addr & 0x03) { 151 151 printk("Attempt to register kprobe at an unaligned address\n"); 152 152 ret = -EINVAL; 153 - } else if (IS_MTMSRD(insn) || IS_RFID(insn)) { 154 - printk("Cannot register a kprobe on mtmsr[d]/rfi[d]\n"); 153 + } else if (!can_single_step(ppc_inst_val(insn))) { 154 + printk("Cannot register a kprobe on instructions that can't be single stepped\n"); 155 155 ret = -EINVAL; 156 156 } else if ((unsigned long)p->addr & ~PAGE_MASK && 157 157 ppc_inst_prefixed(ppc_inst_read(p->addr - 1))) {
+5
arch/powerpc/kernel/uprobes.c
··· 48 48 return -EINVAL; 49 49 } 50 50 51 + if (!can_single_step(ppc_inst_val(ppc_inst_read(auprobe->insn)))) { 52 + pr_info_ratelimited("Cannot register a uprobe on instructions that can't be single stepped\n"); 53 + return -ENOTSUPP; 54 + } 55 + 51 56 return 0; 52 57 } 53 58
+5 -6
arch/powerpc/xmon/xmon.c
··· 921 921 bp->enabled = 0; 922 922 continue; 923 923 } 924 - if (IS_MTMSRD(instr) || IS_RFID(instr)) { 925 - printf("Breakpoint at %lx is on an mtmsrd or rfid " 926 - "instruction, disabling it\n", bp->address); 924 + if (!can_single_step(ppc_inst_val(instr))) { 925 + printf("Breakpoint at %lx is on an instruction that can't be single stepped, disabling it\n", 926 + bp->address); 927 927 bp->enabled = 0; 928 928 continue; 929 929 } ··· 1470 1470 printf("Can't read instruction at address %lx\n", addr); 1471 1471 return 0; 1472 1472 } 1473 - if (IS_MTMSRD(instr) || IS_RFID(instr)) { 1474 - printf("Breakpoints may not be placed on mtmsrd or rfid " 1475 - "instructions\n"); 1473 + if (!can_single_step(ppc_inst_val(instr))) { 1474 + printf("Breakpoints may not be placed on instructions that can't be single stepped\n"); 1476 1475 return 0; 1477 1476 } 1478 1477 return 1;