From: Naveen N. Rao <hidden> Date: 2021-05-19 10:48:22
Various fixes and some code refactoring for kprobes on powerpc. The
first patch fixes an invalid access if probing the first instruction in
a kernel module. The rest are small cleanups. More details in the
individual patches.
- Naveen
Naveen N. Rao (5):
powerpc/kprobes: Fix validation of prefixed instructions across page
boundary
powerpc/kprobes: Roll IS_RFI() macro into IS_RFID()
powerpc/kprobes: Check instruction validity during kprobe registration
powerpc/kprobes: Refactor arch_prepare_kprobe()
powerpc/kprobes: Warn if instruction patching failed
arch/powerpc/include/asm/sstep.h | 7 +-
arch/powerpc/kernel/kprobes.c | 112 +++++++++++--------------------
2 files changed, 43 insertions(+), 76 deletions(-)
base-commit: 3a81c0495fdb91fd9a9b4f617098c283131eeae1
--
2.30.2
From: Naveen N. Rao <hidden> Date: 2021-05-19 10:48:47
When checking if the probed instruction is the suffix of a prefixed
instruction, we access the instruction at the previous word. If the
probed instruction is the very first word of a module, we can end up
trying to access an invalid page. Fix this by skipping the check for all
instructions at the beginning of a page. Prefixed instructions cannot
cross a 64-byte boundary and as such, preventing probing on such
instructions is not worthwhile.
Cc: stable@vger.kernel.org # v5.8+
Fixes: b4657f7650babc ("powerpc/kprobes: Don't allow breakpoints on suffixes")
Reported-by: Christophe Leroy <redacted>
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/kprobes.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
@@ -108,7 +108,6 @@ int arch_prepare_kprobe(struct kprobe *p)intret=0;structkprobe*prev;structppc_instinsn=ppc_inst_read((structppc_inst*)p->addr);-structppc_instprefix=ppc_inst_read((structppc_inst*)(p->addr-1));if((unsignedlong)p->addr&0x03){printk("Attempt to register kprobe at an unaligned address\n");
@@ -116,7 +115,8 @@ int arch_prepare_kprobe(struct kprobe *p)}elseif(IS_MTMSRD(insn)||IS_RFID(insn)||IS_RFI(insn)){printk("Cannot register a kprobe on rfi/rfid or mtmsr[d]\n");ret=-EINVAL;-}elseif(ppc_inst_prefixed(prefix)){+}elseif((unsignedlong)p->addr&~PAGE_MASK&&+ppc_inst_prefixed(ppc_inst_read((structppc_inst*)(p->addr-1)))){printk("Cannot register a kprobe on the second word of prefixed instruction\n");ret=-EINVAL;}
From: Naveen N. Rao <hidden> Date: 2021-05-19 10:49:12
In kprobes and xmon, we should exclude both 32-bit and 64-bit variants
of mtmsr and rfi instructions from being stepped. Have IS_RFID() also
detect a rfi instruction similar to IS_MTMSRD().
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/include/asm/sstep.h | 7 +++----
arch/powerpc/kernel/kprobes.c | 4 ++--
2 files changed, 5 insertions(+), 6 deletions(-)
@@ -112,8 +112,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)||IS_RFI(insn)){-printk("Cannot register a kprobe on rfi/rfid or mtmsr[d]\n");+}elseif(IS_MTMSRD(insn)||IS_RFID(insn)){+printk("Cannot register a kprobe on mtmsr[d]/rfi[d]\n");ret=-EINVAL;}elseif((unsignedlong)p->addr&~PAGE_MASK&&ppc_inst_prefixed(ppc_inst_read((structppc_inst*)(p->addr-1)))){
From: Naveen N. Rao <hidden> Date: 2021-05-19 10:49:36
In trap-based (classic) kprobes, we try to emulate the probed
instruction so as to avoid having to single step it. We use a flag to
determine if the probed instruction was successfully emulated, so that we
can speed up subsequent probe hits.
However, emulate_step() doesn't differentiate between unknown
instructions and an emulation attempt that failed. As such, the current
heuristic is not of much use. Instead, use analyse_instr() during kprobe
registration to determine if the probed instruction can be decoded by
our instruction emulation infrastructure. For unknown instructions, we
can then directly single-step while for other instructions, we can
attempt to emulate and fall back to single stepping if that fails.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/kprobes.c | 62 +++++++++--------------------------
1 file changed, 16 insertions(+), 46 deletions(-)
@@ -107,6 +107,8 @@ int arch_prepare_kprobe(struct kprobe *p){intret=0;structkprobe*prev;+structpt_regsregs;+structinstruction_opop;structppc_instinsn=ppc_inst_read((structppc_inst*)p->addr);if((unsignedlong)p->addr&0x03){
@@ -140,9 +142,18 @@ int arch_prepare_kprobe(struct kprobe *p)if(!ret){patch_instruction((structppc_inst*)p->ainsn.insn,insn);p->opcode=ppc_inst_val(insn);++/* Check if this is an instruction we recognise */+p->ainsn.boostable=0;+memset(®s,0,sizeof(structpt_regs));+regs.nip=(unsignedlong)p->addr;+regs.msr=MSR_KERNEL;+ret=analyse_instr(&op,®s,insn);+if(ret==1||(ret==0&&GETTYPE(op.type)!=UNKNOWN))+p->ainsn.boostable=1;+ret=0;}-p->ainsn.boostable=0;returnret;}NOKPROBE_SYMBOL(arch_prepare_kprobe);
@@ -225,47 +236,6 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)}NOKPROBE_SYMBOL(arch_prepare_kretprobe);-staticinttry_to_emulate(structkprobe*p,structpt_regs*regs)-{-intret;-structppc_instinsn=ppc_inst_read((structppc_inst*)p->ainsn.insn);--/* regs->nip is also adjusted if emulate_step returns 1 */-ret=emulate_step(regs,insn);-if(ret>0){-/*-*Oncethisinstructionhasbeenboosted-*successfully,settheboostableflag-*/-if(unlikely(p->ainsn.boostable==0))-p->ainsn.boostable=1;-}elseif(ret<0){-/*-*Wedon'tallowkprobesonmtmsr(d)/rfi(d),etc.-*So,weshouldnevergethere...but,itsstill-*goodtocatchthem,justincase...-*/-printk("Can't step on instruction %s\n",ppc_inst_as_str(insn));-BUG();-}else{-/*-*Ifwehaven'tpreviouslyemulatedthisinstruction,thenit-*can'tbeboosted.Noteitdownsowedon'ttrytodosoagain.-*-*If,however,wehademulatedthisinstructioninthepast,-*thenthisisjustanerrorwiththecurrentrun(for-*instance,exceptionsduetoaload/store).Wereturn0so-*thatthisisnowsingle-stepped,butcontinuetotry-*emulatingitinsubsequentprobehits.-*/-if(unlikely(p->ainsn.boostable!=1))-p->ainsn.boostable=-1;-}--returnret;-}-NOKPROBE_SYMBOL(try_to_emulate);-intkprobe_handler(structpt_regs*regs){structkprobe*p;
@@ -334,8 +304,8 @@ int kprobe_handler(struct pt_regs *regs)set_current_kprobe(p,regs,kcb);kprobes_inc_nmissed_count(p);kcb->kprobe_status=KPROBE_REENTER;-if(p->ainsn.boostable>=0){-ret=try_to_emulate(p,regs);+if(p->ainsn.boostable){+ret=emulate_step(regs,ppc_inst_read((structppc_inst*)p->ainsn.insn));if(ret>0){restore_previous_kprobe(kcb);
@@ -356,8 +326,8 @@ int kprobe_handler(struct pt_regs *regs)return1;}-if(p->ainsn.boostable>=0){-ret=try_to_emulate(p,regs);+if(p->ainsn.boostable){+ret=emulate_step(regs,ppc_inst_read((structppc_inst*)p->ainsn.insn));if(ret>0){if(p->post_handler)
From: Naveen N. Rao <hidden> Date: 2021-05-19 10:50:11
Clean up the function to look sane:
- return immediately on error, rather than pointlessly setting the
return value
- pr_info() instead of printk()
- check return value of patch_instruction()
- and to top it all of: a reverse christmas tree!
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/kprobes.c | 64 +++++++++++++++++------------------
1 file changed, 31 insertions(+), 33 deletions(-)
@@ -105,56 +105,54 @@ kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset)intarch_prepare_kprobe(structkprobe*p){-intret=0;+structppc_instinsn=ppc_inst_read((structppc_inst*)p->addr);+structinstruction_opop;structkprobe*prev;structpt_regsregs;-structinstruction_opop;-structppc_instinsn=ppc_inst_read((structppc_inst*)p->addr);+intret=0;if((unsignedlong)p->addr&0x03){-printk("Attempt to register kprobe at an unaligned address\n");-ret=-EINVAL;+pr_info("Attempt to register kprobe at an unaligned address\n");+return-EINVAL;}elseif(IS_MTMSRD(insn)||IS_RFID(insn)){-printk("Cannot register a kprobe on mtmsr[d]/rfi[d]\n");-ret=-EINVAL;+pr_info("Cannot register a kprobe on mtmsr[d]/rfi[d]\n");+return-EINVAL;}elseif((unsignedlong)p->addr&~PAGE_MASK&&ppc_inst_prefixed(ppc_inst_read((structppc_inst*)(p->addr-1)))){-printk("Cannot register a kprobe on the second word of prefixed instruction\n");-ret=-EINVAL;+pr_info("Cannot register a kprobe on the second word of prefixed instruction\n");+return-EINVAL;}++/* Check if the previous instruction is a prefix instruction with an active kprobe */preempt_disable();prev=get_kprobe(p->addr-1);preempt_enable_no_resched();-if(prev&&-ppc_inst_prefixed(ppc_inst_read((structppc_inst*)prev->ainsn.insn))){-printk("Cannot register a kprobe on the second word of prefixed instruction\n");-ret=-EINVAL;+if(prev&&ppc_inst_prefixed(ppc_inst_read((structppc_inst*)prev->ainsn.insn))){+pr_info("Cannot register a kprobe on the second word of prefixed instruction\n");+return-EINVAL;}/* insn must be on a special executable page on ppc64. This is*notexplicitlyrequiredonppc32(rightnow),butitdoesn'thurt*/-if(!ret){-p->ainsn.insn=get_insn_slot();-if(!p->ainsn.insn)-ret=-ENOMEM;-}+p->ainsn.insn=get_insn_slot();+if(!p->ainsn.insn)+return-ENOMEM;-if(!ret){-patch_instruction((structppc_inst*)p->ainsn.insn,insn);-p->opcode=ppc_inst_val(insn);--/* Check if this is an instruction we recognise */-p->ainsn.boostable=0;-memset(®s,0,sizeof(structpt_regs));-regs.nip=(unsignedlong)p->addr;-regs.msr=MSR_KERNEL;-ret=analyse_instr(&op,®s,insn);-if(ret==1||(ret==0&&GETTYPE(op.type)!=UNKNOWN))-p->ainsn.boostable=1;-ret=0;-}+if(patch_instruction((structppc_inst*)p->ainsn.insn,insn))+return-EFAULT;-returnret;+p->opcode=ppc_inst_val(insn);++/* Check if this is an instruction we recognise */+p->ainsn.boostable=0;+memset(®s,0,sizeof(structpt_regs));+regs.nip=(unsignedlong)p->addr;+regs.msr=MSR_KERNEL;+ret=analyse_instr(&op,®s,insn);+if(ret==1||(ret==0&&GETTYPE(op.type)!=UNKNOWN))+p->ainsn.boostable=1;++return0;}NOKPROBE_SYMBOL(arch_prepare_kprobe);
From: Naveen N. Rao <hidden> Date: 2021-05-19 10:50:35
When arming and disarming probes, we currently assume that instruction
patching can never fail, and don't have a mechanism to surface errors.
Add a warning in case instruction patching ever fails.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/kprobes.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Michael Ellerman <hidden> Date: 2021-06-06 11:36:29
On Wed, 19 May 2021 16:17:16 +0530, Naveen N. Rao wrote:
Various fixes and some code refactoring for kprobes on powerpc. The
first patch fixes an invalid access if probing the first instruction in
a kernel module. The rest are small cleanups. More details in the
individual patches.
- Naveen
[...]
From: Michael Ellerman <hidden> Date: 2021-06-26 10:43:17
On Wed, 19 May 2021 16:17:16 +0530, Naveen N. Rao wrote:
Various fixes and some code refactoring for kprobes on powerpc. The
first patch fixes an invalid access if probing the first instruction in
a kernel module. The rest are small cleanups. More details in the
individual patches.
- Naveen
[...]
From: Michael Ellerman <hidden> Date: 2021-06-26 10:48:14
On Wed, 19 May 2021 16:17:16 +0530, Naveen N. Rao wrote:
Various fixes and some code refactoring for kprobes on powerpc. The
first patch fixes an invalid access if probing the first instruction in
a kernel module. The rest are small cleanups. More details in the
individual patches.
- Naveen
[...]