On Thu, 5 Jun 2025 15:23:31 +0200 Jiri Olsa <jo...@kernel.org> wrote:
> Adding uprobe_write function that does what uprobe_write_opcode did > so far, but allows to pass verify callback function that checks the > memory location before writing the opcode. > > It will be used in following changes to implement specific checking > logic for instruction update. > > The uprobe_write_opcode now calls uprobe_write with verify_opcode as > the verify callback. > Looks good to me. Acked-by: Masami Hiramatsu (Google) <mhira...@kernel.org> Thanks, > Acked-by: Oleg Nesterov <o...@redhat.com> > Signed-off-by: Jiri Olsa <jo...@kernel.org> > --- > include/linux/uprobes.h | 5 +++++ > kernel/events/uprobes.c | 14 ++++++++++---- > 2 files changed, 15 insertions(+), 4 deletions(-) > > diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h > index 7447e15559b8..e13382054435 100644 > --- a/include/linux/uprobes.h > +++ b/include/linux/uprobes.h > @@ -187,6 +187,9 @@ struct uprobes_state { > struct xol_area *xol_area; > }; > > +typedef int (*uprobe_write_verify_t)(struct page *page, unsigned long vaddr, > + uprobe_opcode_t *opcode); > + > extern void __init uprobes_init(void); > extern int set_swbp(struct arch_uprobe *aup, struct vm_area_struct *vma, > unsigned long vaddr); > extern int set_orig_insn(struct arch_uprobe *aup, struct vm_area_struct > *vma, unsigned long vaddr); > @@ -195,6 +198,8 @@ extern bool is_trap_insn(uprobe_opcode_t *insn); > extern unsigned long uprobe_get_swbp_addr(struct pt_regs *regs); > extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs); > extern int uprobe_write_opcode(struct arch_uprobe *auprobe, struct > vm_area_struct *vma, unsigned long vaddr, uprobe_opcode_t); > +extern int uprobe_write(struct arch_uprobe *auprobe, struct vm_area_struct > *vma, const unsigned long opcode_vaddr, > + uprobe_opcode_t opcode, uprobe_write_verify_t verify); > extern struct uprobe *uprobe_register(struct inode *inode, loff_t offset, > loff_t ref_ctr_offset, struct uprobe_consumer *uc); > extern int uprobe_apply(struct uprobe *uprobe, struct uprobe_consumer *uc, > bool); > extern void uprobe_unregister_nosync(struct uprobe *uprobe, struct > uprobe_consumer *uc); > diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c > index 37d3a3f6e48a..777de9b95dd7 100644 > --- a/kernel/events/uprobes.c > +++ b/kernel/events/uprobes.c > @@ -399,7 +399,7 @@ static bool orig_page_is_identical(struct vm_area_struct > *vma, > return identical; > } > > -static int __uprobe_write_opcode(struct vm_area_struct *vma, > +static int __uprobe_write(struct vm_area_struct *vma, > struct folio_walk *fw, struct folio *folio, > unsigned long opcode_vaddr, uprobe_opcode_t opcode) > { > @@ -488,6 +488,12 @@ static int __uprobe_write_opcode(struct vm_area_struct > *vma, > */ > int uprobe_write_opcode(struct arch_uprobe *auprobe, struct vm_area_struct > *vma, > const unsigned long opcode_vaddr, uprobe_opcode_t opcode) > +{ > + return uprobe_write(auprobe, vma, opcode_vaddr, opcode, verify_opcode); > +} > + > +int uprobe_write(struct arch_uprobe *auprobe, struct vm_area_struct *vma, > + const unsigned long opcode_vaddr, uprobe_opcode_t opcode, > uprobe_write_verify_t verify) > { > const unsigned long vaddr = opcode_vaddr & PAGE_MASK; > struct mm_struct *mm = vma->vm_mm; > @@ -510,7 +516,7 @@ int uprobe_write_opcode(struct arch_uprobe *auprobe, > struct vm_area_struct *vma, > * page that we can safely modify. Use FOLL_WRITE to trigger a write > * fault if required. When unregistering, we might be lucky and the > * anon page is already gone. So defer write faults until really > - * required. Use FOLL_SPLIT_PMD, because __uprobe_write_opcode() > + * required. Use FOLL_SPLIT_PMD, because __uprobe_write() > * cannot deal with PMDs yet. > */ > if (is_register) > @@ -522,7 +528,7 @@ int uprobe_write_opcode(struct arch_uprobe *auprobe, > struct vm_area_struct *vma, > goto out; > folio = page_folio(page); > > - ret = verify_opcode(page, opcode_vaddr, &opcode); > + ret = verify(page, opcode_vaddr, &opcode); > if (ret <= 0) { > folio_put(folio); > goto out; > @@ -561,7 +567,7 @@ int uprobe_write_opcode(struct arch_uprobe *auprobe, > struct vm_area_struct *vma, > /* Walk the page tables again, to perform the actual update. */ > if (folio_walk_start(&fw, vma, vaddr, 0)) { > if (fw.page == page) > - ret = __uprobe_write_opcode(vma, &fw, folio, > opcode_vaddr, opcode); > + ret = __uprobe_write(vma, &fw, folio, opcode_vaddr, > opcode); > folio_walk_end(&fw, vma); > } > > -- > 2.49.0 > -- Masami Hiramatsu (Google) <mhira...@kernel.org>