Skip to content

kprobes: rethook,ARM,arm64: Replace kretprobe trampoline with rethook #255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/actions/vmtest/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: 'vmtest'
description: 'Build + run vmtest'
inputs:
arch:
description: 'what arch to test'
required: true
default: 'x86_64'
runs:
using: "composite"
steps:
# 1. Setup environment
- name: Setup build environment
uses: libbpf/ci/setup-build-env@master
# 2. Build
- name: Build kernel image
shell: bash
run: ${GITHUB_ACTION_PATH}/build.sh ${{ inputs.arch }}
- name: Build selftests
shell: bash
run: ${GITHUB_ACTION_PATH}/build_selftests.sh
env:
VMLINUX_BTF: ${{ github.workspace }}/vmlinux
# 3. Test
- name: Prepare rootfs
uses: libbpf/ci/prepare-rootfs@master
with:
project-name: 'libbpf'
arch: ${{ inputs.arch }}
kernel-root: '.'
- name: Run selftests
uses: libbpf/ci/run-qemu@master
with:
arch: ${{ inputs.arch}}
img: '/tmp/root.img'
vmlinuz: '${{ github.workspace }}/vmlinuz'
17 changes: 17 additions & 0 deletions .github/actions/vmtest/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

set -euo pipefail

ARCH="$1"

THISDIR="$(cd $(dirname $0) && pwd)"

source "${THISDIR}"/helpers.sh

travis_fold start build_kernel "Building kernel"

cp ${GITHUB_WORKSPACE}/travis-ci/vmtest/configs/config-latest.${ARCH} .config

make -j $((4*$(nproc))) olddefconfig all > /dev/null

travis_fold end build_kernel
42 changes: 42 additions & 0 deletions .github/actions/vmtest/build_selftests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash

set -euo pipefail

THISDIR="$(cd $(dirname $0) && pwd)"

source "${THISDIR}"/helpers.sh

travis_fold start prepare_selftests "Building selftests"

LLVM_VER=15
LIBBPF_PATH="${REPO_ROOT}"

PREPARE_SELFTESTS_SCRIPT=${THISDIR}/prepare_selftests-${KERNEL}.sh
if [ -f "${PREPARE_SELFTESTS_SCRIPT}" ]; then
(cd "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" && ${PREPARE_SELFTESTS_SCRIPT})
fi

if [[ "${KERNEL}" = 'LATEST' ]]; then
VMLINUX_H=
else
VMLINUX_H=${THISDIR}/vmlinux.h
fi

cd ${REPO_ROOT}/${REPO_PATH}
make \
CLANG=clang-${LLVM_VER} \
LLC=llc-${LLVM_VER} \
LLVM_STRIP=llvm-strip-${LLVM_VER} \
VMLINUX_BTF="${VMLINUX_BTF}" \
VMLINUX_H="${VMLINUX_H}" \
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
-j $((4*$(nproc))) > /dev/null
cd -
mkdir "${LIBBPF_PATH}"/selftests
cp -R "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
"${LIBBPF_PATH}"/selftests
cd "${LIBBPF_PATH}"
rm selftests/bpf/.gitignore
git add selftests

travis_fold end prepare_selftests
44 changes: 44 additions & 0 deletions .github/actions/vmtest/helpers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# $1 - start or end
# $2 - fold identifier, no spaces
# $3 - fold section description
travis_fold() {
local YELLOW='\033[1;33m'
local NOCOLOR='\033[0m'
if [ -z ${GITHUB_WORKFLOW+x} ]; then
echo travis_fold:$1:$2
if [ ! -z "${3:-}" ]; then
echo -e "${YELLOW}$3${NOCOLOR}"
fi
echo
else
if [ $1 = "start" ]; then
line="::group::$2"
if [ ! -z "${3:-}" ]; then
line="$line - ${YELLOW}$3${NOCOLOR}"
fi
else
line="::endgroup::"
fi
echo -e "$line"
fi
}

__print() {
local TITLE=""
if [[ -n $2 ]]; then
TITLE=" title=$2"
fi
echo "::$1${TITLE}::$3"
}

# $1 - title
# $2 - message
print_error() {
__print error $1 $2
}

# $1 - title
# $2 - message
print_notice() {
__print notice $1 $2
}
50 changes: 50 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: bpf-ci

on:
pull_request:

concurrency:
group: ci-test-${{ github.head_ref }}
cancel-in-progress: true

jobs:
VM_Test:
runs-on: ${{ matrix.runs_on }}
name: Kernel ${{ matrix.kernel }} on ${{ matrix.runs_on }} + selftests
timeout-minutes: 100
strategy:
fail-fast: false
matrix:
include:
- kernel: 'LATEST'
runs_on: ubuntu-latest
arch: 'x86_64'
- kernel: 'LATEST'
runs_on: z15
arch: 's390x'
env:
AUTHOR_EMAIL: "$(git log -1 --pretty=\"%aE\")"
KERNEL: LATEST
REPO_ROOT: ${{ github.workspace }}
REPO_PATH: ""
steps:
- uses: actions/checkout@v2
- if: ${{ github.repository != 'kernel-patches/bpf' && github.repository != 'kernel-patches/bpf-rc' }}
name: Download bpf-next tree
uses: libbpf/ci/get-linux-source@master
with:
dest: '.kernel'
- if: ${{ github.repository != 'kernel-patches/bpf' && github.repository != 'kernel-patches/bpf-rc' }}
name: Move linux source in place
shell: bash
run: |
rm -rf .kernel/.git
cp -rf .kernel/. .
rm -rf .kernel
- uses: libbpf/ci/patch-kernel@master
with:
patches-root: '${{ github.workspace }}/travis-ci/diffs'
repo-root: '${{ github.workspace }}'
- uses: ./.github/actions/vmtest
with:
arch: ${{ matrix.arch }}
18 changes: 0 additions & 18 deletions README
Original file line number Diff line number Diff line change
@@ -1,18 +0,0 @@
Linux kernel
============

There are several guides for kernel developers and users. These guides can
be rendered in a number of formats, like HTML and PDF. Please read
Documentation/admin-guide/README.rst first.

In order to build the documentation, use ``make htmldocs`` or
``make pdfdocs``. The formatted documentation can also be read online at:

https://www.kernel.org/doc/html/latest/

There are various text files in the Documentation/ subdirectory,
several of them using the Restructured Text markup notation.

Please read the Documentation/process/changes.rst file, as it contains the
requirements for building and running the kernel, and information about
the problems which may result by upgrading your kernel.
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ config ARM
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI
select HAVE_OPTPROBES if !THUMB2_KERNEL
select HAVE_RETHOOK
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
Expand Down
5 changes: 3 additions & 2 deletions arch/arm/include/asm/stacktrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ struct stackframe {

/* address of the LR value on the stack */
unsigned long *lr_addr;
#ifdef CONFIG_KRETPROBES

#if defined(CONFIG_RETHOOK)
struct llist_node *kr_cur;
struct task_struct *tsk;
#endif
Expand All @@ -30,7 +31,7 @@ void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)
frame->sp = regs->ARM_sp;
frame->lr = regs->ARM_lr;
frame->pc = regs->ARM_pc;
#ifdef CONFIG_KRETPROBES
#if defined(CONFIG_RETHOOK)
frame->kr_cur = NULL;
frame->tsk = current;
#endif
Expand Down
13 changes: 7 additions & 6 deletions arch/arm/kernel/stacktrace.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/export.h>
#include <linux/kprobes.h>
#include <linux/rethook.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/stacktrace.h>
Expand Down Expand Up @@ -66,10 +67,10 @@ int notrace unwind_frame(struct stackframe *frame)
frame->sp = *(unsigned long *)(fp - 8);
frame->pc = *(unsigned long *)(fp - 4);
#endif
#ifdef CONFIG_KRETPROBES
if (is_kretprobe_trampoline(frame->pc))
frame->pc = kretprobe_find_ret_addr(frame->tsk,
(void *)frame->fp, &frame->kr_cur);
#ifdef CONFIG_RETHOOK
if (is_rethook_trampoline(frame->pc))
frame->pc = rethook_find_ret_addr(frame->tsk, frame->fp,
&frame->kr_cur);
#endif

return 0;
Expand Down Expand Up @@ -163,7 +164,7 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
here:
frame.pc = (unsigned long)&&here;
}
#ifdef CONFIG_KRETPROBES
#ifdef CONFIG_RETHOOK
frame.kr_cur = NULL;
frame.tsk = tsk;
#endif
Expand All @@ -184,7 +185,7 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
frame.sp = regs->ARM_sp;
frame.lr = regs->ARM_lr;
frame.pc = regs->ARM_pc;
#ifdef CONFIG_KRETPROBES
#ifdef CONFIG_RETHOOK
frame.kr_cur = NULL;
frame.tsk = current;
#endif
Expand Down
1 change: 1 addition & 0 deletions arch/arm/kernel/unwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ int unwind_frame(struct stackframe *frame)
ctrl.vrs[SP] = frame->sp;
ctrl.vrs[LR] = frame->lr;
ctrl.vrs[PC] = 0;
ctrl.lr_addr = NULL;

if (idx->insn == 1)
/* can't unwind */
Expand Down
1 change: 1 addition & 0 deletions arch/arm/probes/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ obj-$(CONFIG_KPROBES) += decode-thumb.o
else
obj-$(CONFIG_KPROBES) += decode-arm.o
endif
obj-$(CONFIG_RETHOOK) += rethook.o
62 changes: 0 additions & 62 deletions arch/arm/probes/kprobes/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,68 +365,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
return NOTIFY_DONE;
}

/*
* When a retprobed function returns, trampoline_handler() is called,
* calling the kretprobe's handler. We construct a struct pt_regs to
* give a view of registers r0-r11, sp, lr, and pc to the user
* return-handler. This is not a complete pt_regs structure, but that
* should be enough for stacktrace from the return handler with or
* without pt_regs.
*/
void __naked __kprobes __kretprobe_trampoline(void)
{
__asm__ __volatile__ (
#ifdef CONFIG_FRAME_POINTER
"ldr lr, =__kretprobe_trampoline \n\t"
/* __kretprobe_trampoline makes a framepointer on pt_regs. */
#ifdef CONFIG_CC_IS_CLANG
"stmdb sp, {sp, lr, pc} \n\t"
"sub sp, sp, #12 \n\t"
/* In clang case, pt_regs->ip = lr. */
"stmdb sp!, {r0 - r11, lr} \n\t"
/* fp points regs->r11 (fp) */
"add fp, sp, #44 \n\t"
#else /* !CONFIG_CC_IS_CLANG */
/* In gcc case, pt_regs->ip = fp. */
"stmdb sp, {fp, sp, lr, pc} \n\t"
"sub sp, sp, #16 \n\t"
"stmdb sp!, {r0 - r11} \n\t"
/* fp points regs->r15 (pc) */
"add fp, sp, #60 \n\t"
#endif /* CONFIG_CC_IS_CLANG */
#else /* !CONFIG_FRAME_POINTER */
"sub sp, sp, #16 \n\t"
"stmdb sp!, {r0 - r11} \n\t"
#endif /* CONFIG_FRAME_POINTER */
"mov r0, sp \n\t"
"bl trampoline_handler \n\t"
"mov lr, r0 \n\t"
"ldmia sp!, {r0 - r11} \n\t"
"add sp, sp, #16 \n\t"
#ifdef CONFIG_THUMB2_KERNEL
"bx lr \n\t"
#else
"mov pc, lr \n\t"
#endif
: : : "memory");
}

/* Called from __kretprobe_trampoline */
static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
{
return (void *)kretprobe_trampoline_handler(regs, (void *)regs->ARM_fp);
}

void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
ri->fp = (void *)regs->ARM_fp;

/* Replace the return addr with trampoline addr. */
regs->ARM_lr = (unsigned long)&__kretprobe_trampoline;
}

int __kprobes arch_trampoline_kprobe(struct kprobe *p)
{
return 0;
Expand Down
Loading