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

uprobes: Add nbytes argument to uprobe_write

Adding nbytes argument to uprobe_write and related functions as
preparation for writing whole instructions in following changes.

Also renaming opcode arguments to insn, which seems to fit better.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Link: https://lore.kernel.org/r/20250720112133.244369-6-jolsa@kernel.org

authored by

Jiri Olsa and committed by
Peter Zijlstra
f8b7c528 33d7b2be

+16 -14
+2 -2
include/linux/uprobes.h
··· 188 188 }; 189 189 190 190 typedef int (*uprobe_write_verify_t)(struct page *page, unsigned long vaddr, 191 - uprobe_opcode_t *opcode); 191 + uprobe_opcode_t *insn, int nbytes); 192 192 193 193 extern void __init uprobes_init(void); 194 194 extern int set_swbp(struct arch_uprobe *aup, struct vm_area_struct *vma, unsigned long vaddr); ··· 199 199 extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs); 200 200 extern int uprobe_write_opcode(struct arch_uprobe *auprobe, struct vm_area_struct *vma, unsigned long vaddr, uprobe_opcode_t); 201 201 extern int uprobe_write(struct arch_uprobe *auprobe, struct vm_area_struct *vma, const unsigned long opcode_vaddr, 202 - uprobe_opcode_t opcode, uprobe_write_verify_t verify); 202 + uprobe_opcode_t *insn, int nbytes, uprobe_write_verify_t verify); 203 203 extern struct uprobe *uprobe_register(struct inode *inode, loff_t offset, loff_t ref_ctr_offset, struct uprobe_consumer *uc); 204 204 extern int uprobe_apply(struct uprobe *uprobe, struct uprobe_consumer *uc, bool); 205 205 extern void uprobe_unregister_nosync(struct uprobe *uprobe, struct uprobe_consumer *uc);
+14 -12
kernel/events/uprobes.c
··· 191 191 kunmap_atomic(kaddr); 192 192 } 193 193 194 - static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *new_opcode) 194 + static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *insn, 195 + int nbytes) 195 196 { 196 197 uprobe_opcode_t old_opcode; 197 198 bool is_swbp; ··· 209 208 uprobe_copy_from_page(page, vaddr, &old_opcode, UPROBE_SWBP_INSN_SIZE); 210 209 is_swbp = is_swbp_insn(&old_opcode); 211 210 212 - if (is_swbp_insn(new_opcode)) { 211 + if (is_swbp_insn(insn)) { 213 212 if (is_swbp) /* register: already installed? */ 214 213 return 0; 215 214 } else { ··· 402 401 403 402 static int __uprobe_write(struct vm_area_struct *vma, 404 403 struct folio_walk *fw, struct folio *folio, 405 - unsigned long opcode_vaddr, uprobe_opcode_t opcode) 404 + unsigned long insn_vaddr, uprobe_opcode_t *insn, int nbytes) 406 405 { 407 - const unsigned long vaddr = opcode_vaddr & PAGE_MASK; 408 - const bool is_register = !!is_swbp_insn(&opcode); 406 + const unsigned long vaddr = insn_vaddr & PAGE_MASK; 407 + const bool is_register = !!is_swbp_insn(insn); 409 408 bool pmd_mappable; 410 409 411 410 /* For now, we'll only handle PTE-mapped folios. */ ··· 430 429 */ 431 430 flush_cache_page(vma, vaddr, pte_pfn(fw->pte)); 432 431 fw->pte = ptep_clear_flush(vma, vaddr, fw->ptep); 433 - copy_to_page(fw->page, opcode_vaddr, &opcode, UPROBE_SWBP_INSN_SIZE); 432 + copy_to_page(fw->page, insn_vaddr, insn, nbytes); 434 433 435 434 /* 436 435 * When unregistering, we may only zap a PTE if uffd is disabled and ··· 489 488 int uprobe_write_opcode(struct arch_uprobe *auprobe, struct vm_area_struct *vma, 490 489 const unsigned long opcode_vaddr, uprobe_opcode_t opcode) 491 490 { 492 - return uprobe_write(auprobe, vma, opcode_vaddr, opcode, verify_opcode); 491 + return uprobe_write(auprobe, vma, opcode_vaddr, &opcode, UPROBE_SWBP_INSN_SIZE, verify_opcode); 493 492 } 494 493 495 494 int uprobe_write(struct arch_uprobe *auprobe, struct vm_area_struct *vma, 496 - const unsigned long opcode_vaddr, uprobe_opcode_t opcode, uprobe_write_verify_t verify) 495 + const unsigned long insn_vaddr, uprobe_opcode_t *insn, int nbytes, 496 + uprobe_write_verify_t verify) 497 497 { 498 - const unsigned long vaddr = opcode_vaddr & PAGE_MASK; 498 + const unsigned long vaddr = insn_vaddr & PAGE_MASK; 499 499 struct mm_struct *mm = vma->vm_mm; 500 500 struct uprobe *uprobe; 501 501 int ret, is_register, ref_ctr_updated = 0; ··· 506 504 struct folio *folio; 507 505 struct page *page; 508 506 509 - is_register = is_swbp_insn(&opcode); 507 + is_register = is_swbp_insn(insn); 510 508 uprobe = container_of(auprobe, struct uprobe, arch); 511 509 512 510 if (WARN_ON_ONCE(!is_cow_mapping(vma->vm_flags))) ··· 529 527 goto out; 530 528 folio = page_folio(page); 531 529 532 - ret = verify(page, opcode_vaddr, &opcode); 530 + ret = verify(page, insn_vaddr, insn, nbytes); 533 531 if (ret <= 0) { 534 532 folio_put(folio); 535 533 goto out; ··· 568 566 /* Walk the page tables again, to perform the actual update. */ 569 567 if (folio_walk_start(&fw, vma, vaddr, 0)) { 570 568 if (fw.page == page) 571 - ret = __uprobe_write(vma, &fw, folio, opcode_vaddr, opcode); 569 + ret = __uprobe_write(vma, &fw, folio, insn_vaddr, insn, nbytes); 572 570 folio_walk_end(&fw, vma); 573 571 } 574 572