From: Naveen N. Rao <hidden> Date: 2022-03-23 11:53:48
This is an update to the series posted by Nick here:
http://lkml.kernel.org/r/20220124055741.3686496-1-npiggin@gmail.com
The first patch disables probes and breakpoints on instructions that
can't be single stepped, including sc and scv. The second patch removes
system call emulation for powerpc64.
- Naveen
Naveen N. Rao (1):
powerpc: Reject probes on instructions that can't be single stepped
Nicholas Piggin (1):
powerpc/64: remove system call instruction emulation
arch/powerpc/include/asm/probes.h | 55 ++++++++++++++++++++++++++++++
arch/powerpc/kernel/interrupt_64.S | 10 ------
arch/powerpc/kernel/kprobes.c | 4 +--
arch/powerpc/kernel/uprobes.c | 5 +++
arch/powerpc/lib/sstep.c | 46 ++++++-------------------
arch/powerpc/xmon/xmon.c | 11 +++---
6 files changed, 77 insertions(+), 54 deletions(-)
base-commit: e8833c5edc5903f8c8c4fa3dd4f34d6b813c87c8
--
2.35.1
From: Naveen N. Rao <hidden> Date: 2022-03-23 11:53:08
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 <redacted>
---
arch/powerpc/include/asm/probes.h | 55 +++++++++++++++++++++++++++++++
arch/powerpc/kernel/kprobes.c | 4 +--
arch/powerpc/kernel/uprobes.c | 5 +++
arch/powerpc/xmon/xmon.c | 11 +++----
4 files changed, 67 insertions(+), 8 deletions(-)
@@ -129,8 +129,8 @@ int arch_prepare_kprobe(struct kprobe *p)if((unsignedlong)p->addr&0x03){printk("Attempt to register kprobe at an unaligned address\n");ret=-EINVAL;-}elseif(IS_MTMSRD(insn)||IS_RFID(insn)){-printk("Cannot register a kprobe on mtmsr[d]/rfi[d]\n");+}elseif(!can_single_step(ppc_inst_val(insn))){+printk("Cannot register a kprobe on instructions that can't be single stepped\n");ret=-EINVAL;}elseif((unsignedlong)p->addr&~PAGE_MASK&&ppc_inst_prefixed(ppc_inst_read(p->addr-1))){
@@ -48,6 +48,11 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,return-EINVAL;}+if(!can_single_step(ppc_inst_val(ppc_inst_read(auprobe->insn)))){+pr_info_ratelimited("Cannot register a uprobe on instructions that can't be single stepped\n");+return-ENOTSUPP;+}+return0;}
@@ -921,9 +921,9 @@ static void insert_bpts(void)bp->enabled=0;continue;}-if(IS_MTMSRD(instr)||IS_RFID(instr)){-printf("Breakpoint at %lx is on an mtmsrd or rfid "-"instruction, disabling it\n",bp->address);+if(!can_single_step(ppc_inst_val(instr))){+printf("Breakpoint at %lx is on an instruction that can't be single stepped, disabling it\n",+bp->address);bp->enabled=0;continue;}
@@ -1470,9 +1470,8 @@ static long check_bp_loc(unsigned long addr)printf("Can't read instruction at address %lx\n",addr);return0;}-if(IS_MTMSRD(instr)||IS_RFID(instr)){-printf("Breakpoints may not be placed on mtmsrd or rfid "-"instructions\n");+if(!can_single_step(ppc_inst_val(instr))){+printf("Breakpoints may not be placed on instructions that can't be single stepped\n");return0;}return1;
From: Naveen N. Rao <hidden> Date: 2022-03-23 11:54:29
From: Nicholas Piggin <npiggin@gmail.com>
emulate_step instruction emulation including sc instruction emulation
initially appeared in xmon. It then emulation code was then moved into
sstep.c where kprobes could use it too, and later hw_breakpoint and
uprobes started to use it.
Until uprobes, the only instruction emulation users were for kernel
mode instructions.
- xmon only steps / breaks on kernel addresses.
- kprobes is kernel only.
- hw_breakpoint only emulates kernel instructions, single steps user.
At one point there was support for the kernel to execute sc
instructions, although that is long removed and it's not clear whether
there was any in-tree code. So system call emulation is not required by
the above users.
uprobes uses emulate_step and it appears possible to emulate sc
instruction in userspace. Userspace system call emulation is broken and
it's not clear it ever worked well.
The big complication is that userspace takes an interrupt to the kernel
to emulate the instruction. The user->kernel interrupt sets up registers
and interrupt stack frame expecting to return to userspace, then system
call instruction emulation re-directs that stack frame to the kernel,
early in the system call interrupt handler. This means the the interrupt
return code takes the kernel->kernel restore path, which does not restore
everything as the system call interrupt handler would expect coming from
userspace. regs->iamr appears to get lost for example, because the
kernel->kernel return does not restore the user iamr. Accounting such as
irqflags tracing and CPU accounting does not get flipped back to user
mode as the system call handler expects, so those appear to enter the
kernel twice without returning to userspace.
These things may be individually fixable with various complication, but
it is a big complexity for unclear real benefit.
This patch removes system call emulation and disables stepping system
calls (because they don't work with trace interrupts, as commented).
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[also get rid of '#ifdef CONFIG_PPC64']
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/interrupt_64.S | 10 -------
arch/powerpc/lib/sstep.c | 46 +++++++-----------------------
2 files changed, 10 insertions(+), 46 deletions(-)
@@ -15,9 +15,6 @@#include<asm/cputable.h>#include<asm/disassemble.h>-externcharsystem_call_common[];-externcharsystem_call_vectored_emulate[];-#ifdef CONFIG_PPC64/* Bits in SRR1 that are copied from MSR */#define MSR_MASK 0xffffffff87c0ffffUL
Hi, Naveen.
Some comments below.
On 3/23/22 08:51, Naveen N. Rao wrote:
quoted hunk
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 <redacted>
---
arch/powerpc/include/asm/probes.h | 55 +++++++++++++++++++++++++++++++
arch/powerpc/kernel/kprobes.c | 4 +--
arch/powerpc/kernel/uprobes.c | 5 +++
arch/powerpc/xmon/xmon.c | 11 +++----
4 files changed, 67 insertions(+), 8 deletions(-)
@@ -129,8 +129,8 @@ int arch_prepare_kprobe(struct kprobe *p)if((unsignedlong)p->addr&0x03){printk("Attempt to register kprobe at an unaligned address\n");ret=-EINVAL;-}elseif(IS_MTMSRD(insn)||IS_RFID(insn)){-printk("Cannot register a kprobe on mtmsr[d]/rfi[d]\n");+}elseif(!can_single_step(ppc_inst_val(insn))){+printk("Cannot register a kprobe on instructions that can't be single stepped\n");ret=-EINVAL;}elseif((unsignedlong)p->addr&~PAGE_MASK&&ppc_inst_prefixed(ppc_inst_read(p->addr-1))){
@@ -48,6 +48,11 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,return-EINVAL;}+if(!can_single_step(ppc_inst_val(ppc_inst_read(auprobe->insn)))){+pr_info_ratelimited("Cannot register a uprobe on instructions that can't be single stepped\n");+return-ENOTSUPP;+}+return0;}
@@ -921,9 +921,9 @@ static void insert_bpts(void)bp->enabled=0;continue;}-if(IS_MTMSRD(instr)||IS_RFID(instr)){-printf("Breakpoint at %lx is on an mtmsrd or rfid "-"instruction, disabling it\n",bp->address);+if(!can_single_step(ppc_inst_val(instr))){+printf("Breakpoint at %lx is on an instruction that can't be single stepped, disabling it\n",+bp->address);bp->enabled=0;continue;}
@@ -1470,9 +1470,8 @@ static long check_bp_loc(unsigned long addr)printf("Can't read instruction at address %lx\n",addr);return0;}-if(IS_MTMSRD(instr)||IS_RFID(instr)){-printf("Breakpoints may not be placed on mtmsrd or rfid "-"instructions\n");+if(!can_single_step(ppc_inst_val(instr))){+printf("Breakpoints may not be placed on instructions that can't be single stepped\n");return0;}return1;
I didn't want to add a dependency on inst.h. But I guess I can very well
move this out of the header into some .c file. I will see if I can make
that work.
I didn't want to add a dependency on inst.h. But I guess I can very well
move this out of the header into some .c file. I will see if I can make
that work.
Maybe use get_op() from asm/disassemble.h ?
quoted
quoted
quoted
+ case 31:
+ switch ((inst >> 1) & 0x3ff) {
For that one you have get_xop() in asm/disassemble.h
I didn't want to add a dependency on inst.h. But I guess I can very well
move this out of the header into some .c file. I will see if I can make
that work.
Maybe use get_op() from asm/disassemble.h ?
quoted
quoted
quoted
quoted
+ case 31:
+ switch ((inst >> 1) & 0x3ff) {
For that one you have get_xop() in asm/disassemble.h