| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * arch/arm/kernel/kprobes.c |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * |
|---|
| 9 | 10 | * Nicolas Pitre <nico@marvell.com> |
|---|
| 10 | 11 | * Copyright (C) 2007 Marvell Ltd. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 13 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 14 | | - * published by the Free Software Foundation. |
|---|
| 15 | | - * |
|---|
| 16 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 17 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 19 | | - * General Public License for more details. |
|---|
| 20 | 12 | */ |
|---|
| 21 | 13 | |
|---|
| 22 | 14 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 288 | 280 | /* A nested probe was hit in FIQ, it is a BUG */ |
|---|
| 289 | 281 | pr_warn("Unrecoverable kprobe detected.\n"); |
|---|
| 290 | 282 | dump_kprobe(p); |
|---|
| 291 | | - /* fall through */ |
|---|
| 283 | + fallthrough; |
|---|
| 292 | 284 | default: |
|---|
| 293 | 285 | /* impossible cases */ |
|---|
| 294 | 286 | BUG(); |
|---|
| .. | .. |
|---|
| 421 | 413 | /* Called from kretprobe_trampoline */ |
|---|
| 422 | 414 | static __used __kprobes void *trampoline_handler(struct pt_regs *regs) |
|---|
| 423 | 415 | { |
|---|
| 424 | | - struct kretprobe_instance *ri = NULL; |
|---|
| 425 | | - struct hlist_head *head, empty_rp; |
|---|
| 426 | | - struct hlist_node *tmp; |
|---|
| 427 | | - unsigned long flags, orig_ret_address = 0; |
|---|
| 428 | | - unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; |
|---|
| 429 | | - kprobe_opcode_t *correct_ret_addr = NULL; |
|---|
| 430 | | - |
|---|
| 431 | | - INIT_HLIST_HEAD(&empty_rp); |
|---|
| 432 | | - kretprobe_hash_lock(current, &head, &flags); |
|---|
| 433 | | - |
|---|
| 434 | | - /* |
|---|
| 435 | | - * It is possible to have multiple instances associated with a given |
|---|
| 436 | | - * task either because multiple functions in the call path have |
|---|
| 437 | | - * a return probe installed on them, and/or more than one return |
|---|
| 438 | | - * probe was registered for a target function. |
|---|
| 439 | | - * |
|---|
| 440 | | - * We can handle this because: |
|---|
| 441 | | - * - instances are always inserted at the head of the list |
|---|
| 442 | | - * - when multiple return probes are registered for the same |
|---|
| 443 | | - * function, the first instance's ret_addr will point to the |
|---|
| 444 | | - * real return address, and all the rest will point to |
|---|
| 445 | | - * kretprobe_trampoline |
|---|
| 446 | | - */ |
|---|
| 447 | | - hlist_for_each_entry_safe(ri, tmp, head, hlist) { |
|---|
| 448 | | - if (ri->task != current) |
|---|
| 449 | | - /* another task is sharing our hash bucket */ |
|---|
| 450 | | - continue; |
|---|
| 451 | | - |
|---|
| 452 | | - orig_ret_address = (unsigned long)ri->ret_addr; |
|---|
| 453 | | - |
|---|
| 454 | | - if (orig_ret_address != trampoline_address) |
|---|
| 455 | | - /* |
|---|
| 456 | | - * This is the real return address. Any other |
|---|
| 457 | | - * instances associated with this task are for |
|---|
| 458 | | - * other calls deeper on the call stack |
|---|
| 459 | | - */ |
|---|
| 460 | | - break; |
|---|
| 461 | | - } |
|---|
| 462 | | - |
|---|
| 463 | | - kretprobe_assert(ri, orig_ret_address, trampoline_address); |
|---|
| 464 | | - |
|---|
| 465 | | - correct_ret_addr = ri->ret_addr; |
|---|
| 466 | | - hlist_for_each_entry_safe(ri, tmp, head, hlist) { |
|---|
| 467 | | - if (ri->task != current) |
|---|
| 468 | | - /* another task is sharing our hash bucket */ |
|---|
| 469 | | - continue; |
|---|
| 470 | | - |
|---|
| 471 | | - orig_ret_address = (unsigned long)ri->ret_addr; |
|---|
| 472 | | - if (ri->rp && ri->rp->handler) { |
|---|
| 473 | | - __this_cpu_write(current_kprobe, &ri->rp->kp); |
|---|
| 474 | | - get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; |
|---|
| 475 | | - ri->ret_addr = correct_ret_addr; |
|---|
| 476 | | - ri->rp->handler(ri, regs); |
|---|
| 477 | | - __this_cpu_write(current_kprobe, NULL); |
|---|
| 478 | | - } |
|---|
| 479 | | - |
|---|
| 480 | | - recycle_rp_inst(ri, &empty_rp); |
|---|
| 481 | | - |
|---|
| 482 | | - if (orig_ret_address != trampoline_address) |
|---|
| 483 | | - /* |
|---|
| 484 | | - * This is the real return address. Any other |
|---|
| 485 | | - * instances associated with this task are for |
|---|
| 486 | | - * other calls deeper on the call stack |
|---|
| 487 | | - */ |
|---|
| 488 | | - break; |
|---|
| 489 | | - } |
|---|
| 490 | | - |
|---|
| 491 | | - kretprobe_hash_unlock(current, &flags); |
|---|
| 492 | | - |
|---|
| 493 | | - hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { |
|---|
| 494 | | - hlist_del(&ri->hlist); |
|---|
| 495 | | - kfree(ri); |
|---|
| 496 | | - } |
|---|
| 497 | | - |
|---|
| 498 | | - return (void *)orig_ret_address; |
|---|
| 416 | + return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline, |
|---|
| 417 | + (void *)regs->ARM_fp); |
|---|
| 499 | 418 | } |
|---|
| 500 | 419 | |
|---|
| 501 | 420 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, |
|---|
| 502 | 421 | struct pt_regs *regs) |
|---|
| 503 | 422 | { |
|---|
| 504 | 423 | ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr; |
|---|
| 424 | + ri->fp = (void *)regs->ARM_fp; |
|---|
| 505 | 425 | |
|---|
| 506 | 426 | /* Replace the return addr with trampoline addr. */ |
|---|
| 507 | 427 | regs->ARM_lr = (unsigned long)&kretprobe_trampoline; |
|---|