Skip to content

Commit ff2dd73

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf-next/master' into for-next
Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents f64f593 + d4680a1 commit ff2dd73

File tree

10 files changed

+290
-4
lines changed

10 files changed

+290
-4
lines changed

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,7 @@ struct bpf_prog_aux {
16391639
bool priv_stack_requested;
16401640
bool changes_pkt_data;
16411641
bool might_sleep;
1642+
bool kprobe_write_ctx;
16421643
u64 prog_array_member_cnt; /* counts how many times as member of prog_array */
16431644
struct mutex ext_mutex; /* mutex for is_extended and prog_array_member_cnt */
16441645
struct bpf_arena *arena;

include/linux/btf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
* as to avoid issues such as the compiler inlining or eliding either a static
8787
* kfunc, or a global kfunc in an LTO build.
8888
*/
89-
#define __bpf_kfunc __used __retain noinline
89+
#define __bpf_kfunc __used __retain __noclone noinline
9090

9191
#define __bpf_kfunc_start_defs() \
9292
__diag_push(); \

kernel/events/core.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11232,6 +11232,10 @@ static int __perf_event_set_bpf_prog(struct perf_event *event,
1123211232
if (prog->kprobe_override && !is_kprobe)
1123311233
return -EINVAL;
1123411234

11235+
/* Writing to context allowed only for uprobes. */
11236+
if (prog->aux->kprobe_write_ctx && !is_uprobe)
11237+
return -EINVAL;
11238+
1123511239
if (is_tracepoint || is_syscall_tp) {
1123611240
int off = trace_event_get_offsets(event->tp_event);
1123711241

kernel/events/uprobes.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2741,6 +2741,13 @@ static void handle_swbp(struct pt_regs *regs)
27412741

27422742
handler_chain(uprobe, regs);
27432743

2744+
/*
2745+
* If user decided to take execution elsewhere, it makes little sense
2746+
* to execute the original instruction, so let's skip it.
2747+
*/
2748+
if (instruction_pointer(regs) != bp_vaddr)
2749+
goto out;
2750+
27442751
if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
27452752
goto out;
27462753

kernel/trace/bpf_trace.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,8 +1338,6 @@ static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type
13381338
{
13391339
if (off < 0 || off >= sizeof(struct pt_regs))
13401340
return false;
1341-
if (type != BPF_READ)
1342-
return false;
13431341
if (off % size != 0)
13441342
return false;
13451343
/*
@@ -1349,6 +1347,9 @@ static bool kprobe_prog_is_valid_access(int off, int size, enum bpf_access_type
13491347
if (off + size > sizeof(struct pt_regs))
13501348
return false;
13511349

1350+
if (type == BPF_WRITE)
1351+
prog->aux->kprobe_write_ctx = true;
1352+
13521353
return true;
13531354
}
13541355

@@ -2735,6 +2736,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
27352736
if (!is_kprobe_multi(prog))
27362737
return -EINVAL;
27372738

2739+
/* Writing to context is not allowed for kprobes. */
2740+
if (prog->aux->kprobe_write_ctx)
2741+
return -EINVAL;
2742+
27382743
flags = attr->link_create.kprobe_multi.flags;
27392744
if (flags & ~BPF_F_KPROBE_MULTI_RETURN)
27402745
return -EINVAL;

tools/testing/selftests/bpf/prog_tests/attach_probe.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "test_attach_kprobe_sleepable.skel.h"
44
#include "test_attach_probe_manual.skel.h"
55
#include "test_attach_probe.skel.h"
6+
#include "kprobe_write_ctx.skel.h"
67

78
/* this is how USDT semaphore is actually defined, except volatile modifier */
89
volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
@@ -201,6 +202,31 @@ static void test_attach_kprobe_long_event_name(void)
201202
test_attach_probe_manual__destroy(skel);
202203
}
203204

205+
#ifdef __x86_64__
206+
/* attach kprobe/kretprobe long event name testings */
207+
static void test_attach_kprobe_write_ctx(void)
208+
{
209+
struct kprobe_write_ctx *skel = NULL;
210+
struct bpf_link *link = NULL;
211+
212+
skel = kprobe_write_ctx__open_and_load();
213+
if (!ASSERT_OK_PTR(skel, "kprobe_write_ctx__open_and_load"))
214+
return;
215+
216+
link = bpf_program__attach_kprobe_opts(skel->progs.kprobe_write_ctx,
217+
"bpf_fentry_test1", NULL);
218+
if (!ASSERT_ERR_PTR(link, "bpf_program__attach_kprobe_opts"))
219+
bpf_link__destroy(link);
220+
221+
kprobe_write_ctx__destroy(skel);
222+
}
223+
#else
224+
static void test_attach_kprobe_write_ctx(void)
225+
{
226+
test__skip();
227+
}
228+
#endif
229+
204230
static void test_attach_probe_auto(struct test_attach_probe *skel)
205231
{
206232
struct bpf_link *uprobe_err_link;
@@ -406,6 +432,8 @@ void test_attach_probe(void)
406432
test_attach_uprobe_long_event_name();
407433
if (test__start_subtest("kprobe-long_name"))
408434
test_attach_kprobe_long_event_name();
435+
if (test__start_subtest("kprobe-write-ctx"))
436+
test_attach_kprobe_write_ctx();
409437

410438
cleanup:
411439
test_attach_probe__destroy(skel);

tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "kprobe_multi_session.skel.h"
88
#include "kprobe_multi_session_cookie.skel.h"
99
#include "kprobe_multi_verifier.skel.h"
10+
#include "kprobe_write_ctx.skel.h"
1011
#include "bpf/libbpf_internal.h"
1112
#include "bpf/hashmap.h"
1213

@@ -539,6 +540,30 @@ static void test_attach_override(void)
539540
kprobe_multi_override__destroy(skel);
540541
}
541542

543+
#ifdef __x86_64__
544+
static void test_attach_write_ctx(void)
545+
{
546+
struct kprobe_write_ctx *skel = NULL;
547+
struct bpf_link *link = NULL;
548+
549+
skel = kprobe_write_ctx__open_and_load();
550+
if (!ASSERT_OK_PTR(skel, "kprobe_write_ctx__open_and_load"))
551+
return;
552+
553+
link = bpf_program__attach_kprobe_opts(skel->progs.kprobe_multi_write_ctx,
554+
"bpf_fentry_test1", NULL);
555+
if (!ASSERT_ERR_PTR(link, "bpf_program__attach_kprobe_opts"))
556+
bpf_link__destroy(link);
557+
558+
kprobe_write_ctx__destroy(skel);
559+
}
560+
#else
561+
static void test_attach_write_ctx(void)
562+
{
563+
test__skip();
564+
}
565+
#endif
566+
542567
void serial_test_kprobe_multi_bench_attach(void)
543568
{
544569
if (test__start_subtest("kernel"))
@@ -578,5 +603,7 @@ void test_kprobe_multi_test(void)
578603
test_session_cookie_skel_api();
579604
if (test__start_subtest("unique_match"))
580605
test_unique_match();
606+
if (test__start_subtest("attach_write_ctx"))
607+
test_attach_write_ctx();
581608
RUN_TESTS(kprobe_multi_verifier);
582609
}

tools/testing/selftests/bpf/prog_tests/uprobe.c

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* Copyright (c) 2023 Hengqi Chen */
33

44
#include <test_progs.h>
5+
#include <asm/ptrace.h>
56
#include "test_uprobe.skel.h"
67

78
static FILE *urand_spawn(int *pid)
@@ -33,7 +34,7 @@ static int urand_trigger(FILE **urand_pipe)
3334
return exit_code;
3435
}
3536

36-
void test_uprobe(void)
37+
static void test_uprobe_attach(void)
3738
{
3839
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
3940
struct test_uprobe *skel;
@@ -93,3 +94,156 @@ void test_uprobe(void)
9394
pclose(urand_pipe);
9495
test_uprobe__destroy(skel);
9596
}
97+
98+
#ifdef __x86_64__
99+
__naked __maybe_unused unsigned long uprobe_regs_change_trigger(void)
100+
{
101+
asm volatile (
102+
"ret\n"
103+
);
104+
}
105+
106+
static __naked void uprobe_regs_change(struct pt_regs *before, struct pt_regs *after)
107+
{
108+
asm volatile (
109+
"movq %r11, 48(%rdi)\n"
110+
"movq %r10, 56(%rdi)\n"
111+
"movq %r9, 64(%rdi)\n"
112+
"movq %r8, 72(%rdi)\n"
113+
"movq %rax, 80(%rdi)\n"
114+
"movq %rcx, 88(%rdi)\n"
115+
"movq %rdx, 96(%rdi)\n"
116+
"movq %rsi, 104(%rdi)\n"
117+
"movq %rdi, 112(%rdi)\n"
118+
119+
/* save 2nd argument */
120+
"pushq %rsi\n"
121+
"call uprobe_regs_change_trigger\n"
122+
123+
/* save return value and load 2nd argument pointer to rax */
124+
"pushq %rax\n"
125+
"movq 8(%rsp), %rax\n"
126+
127+
"movq %r11, 48(%rax)\n"
128+
"movq %r10, 56(%rax)\n"
129+
"movq %r9, 64(%rax)\n"
130+
"movq %r8, 72(%rax)\n"
131+
"movq %rcx, 88(%rax)\n"
132+
"movq %rdx, 96(%rax)\n"
133+
"movq %rsi, 104(%rax)\n"
134+
"movq %rdi, 112(%rax)\n"
135+
136+
/* restore return value and 2nd argument */
137+
"pop %rax\n"
138+
"pop %rsi\n"
139+
140+
"movq %rax, 80(%rsi)\n"
141+
"ret\n"
142+
);
143+
}
144+
145+
static void regs_common(void)
146+
{
147+
struct pt_regs before = {}, after = {}, expected = {
148+
.rax = 0xc0ffe,
149+
.rcx = 0xbad,
150+
.rdx = 0xdead,
151+
.r8 = 0x8,
152+
.r9 = 0x9,
153+
.r10 = 0x10,
154+
.r11 = 0x11,
155+
.rdi = 0x12,
156+
.rsi = 0x13,
157+
};
158+
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
159+
struct test_uprobe *skel;
160+
161+
skel = test_uprobe__open_and_load();
162+
if (!ASSERT_OK_PTR(skel, "skel_open"))
163+
return;
164+
165+
skel->bss->my_pid = getpid();
166+
skel->bss->regs = expected;
167+
168+
uprobe_opts.func_name = "uprobe_regs_change_trigger";
169+
skel->links.test_regs_change = bpf_program__attach_uprobe_opts(skel->progs.test_regs_change,
170+
-1,
171+
"/proc/self/exe",
172+
0 /* offset */,
173+
&uprobe_opts);
174+
if (!ASSERT_OK_PTR(skel->links.test_regs_change, "bpf_program__attach_uprobe_opts"))
175+
goto cleanup;
176+
177+
uprobe_regs_change(&before, &after);
178+
179+
ASSERT_EQ(after.rax, expected.rax, "ax");
180+
ASSERT_EQ(after.rcx, expected.rcx, "cx");
181+
ASSERT_EQ(after.rdx, expected.rdx, "dx");
182+
ASSERT_EQ(after.r8, expected.r8, "r8");
183+
ASSERT_EQ(after.r9, expected.r9, "r9");
184+
ASSERT_EQ(after.r10, expected.r10, "r10");
185+
ASSERT_EQ(after.r11, expected.r11, "r11");
186+
ASSERT_EQ(after.rdi, expected.rdi, "rdi");
187+
ASSERT_EQ(after.rsi, expected.rsi, "rsi");
188+
189+
cleanup:
190+
test_uprobe__destroy(skel);
191+
}
192+
193+
static noinline unsigned long uprobe_regs_change_ip_1(void)
194+
{
195+
return 0xc0ffee;
196+
}
197+
198+
static noinline unsigned long uprobe_regs_change_ip_2(void)
199+
{
200+
return 0xdeadbeef;
201+
}
202+
203+
static void regs_ip(void)
204+
{
205+
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
206+
struct test_uprobe *skel;
207+
unsigned long ret;
208+
209+
skel = test_uprobe__open_and_load();
210+
if (!ASSERT_OK_PTR(skel, "skel_open"))
211+
return;
212+
213+
skel->bss->my_pid = getpid();
214+
skel->bss->ip = (unsigned long) uprobe_regs_change_ip_2;
215+
216+
uprobe_opts.func_name = "uprobe_regs_change_ip_1";
217+
skel->links.test_regs_change_ip = bpf_program__attach_uprobe_opts(
218+
skel->progs.test_regs_change_ip,
219+
-1,
220+
"/proc/self/exe",
221+
0 /* offset */,
222+
&uprobe_opts);
223+
if (!ASSERT_OK_PTR(skel->links.test_regs_change_ip, "bpf_program__attach_uprobe_opts"))
224+
goto cleanup;
225+
226+
ret = uprobe_regs_change_ip_1();
227+
ASSERT_EQ(ret, 0xdeadbeef, "ret");
228+
229+
cleanup:
230+
test_uprobe__destroy(skel);
231+
}
232+
233+
static void test_uprobe_regs_change(void)
234+
{
235+
if (test__start_subtest("regs_change_common"))
236+
regs_common();
237+
if (test__start_subtest("regs_change_ip"))
238+
regs_ip();
239+
}
240+
#else
241+
static void test_uprobe_regs_change(void) { }
242+
#endif
243+
244+
void test_uprobe(void)
245+
{
246+
if (test__start_subtest("attach"))
247+
test_uprobe_attach();
248+
test_uprobe_regs_change();
249+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include "vmlinux.h"
3+
#include <bpf/bpf_helpers.h>
4+
#include <bpf/bpf_tracing.h>
5+
6+
char _license[] SEC("license") = "GPL";
7+
8+
#if defined(__TARGET_ARCH_x86)
9+
SEC("kprobe")
10+
int kprobe_write_ctx(struct pt_regs *ctx)
11+
{
12+
ctx->ax = 0;
13+
return 0;
14+
}
15+
16+
SEC("kprobe.multi")
17+
int kprobe_multi_write_ctx(struct pt_regs *ctx)
18+
{
19+
ctx->ax = 0;
20+
return 0;
21+
}
22+
#endif

0 commit comments

Comments
 (0)