bpf-for-netdev
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQTFp0I1jqZrAX+hPRXbK58LschIgwUCZUsiDAAKCRDbK58LschI g9xXAQCaFjj55sXDpr1qKG2D3PMSDURx7SzmpzIay/A/dqVDPgEAlgU6XsMW6w6S poMN8KniDLtBgj6nIKfJEAgIXeIYTAs= =qXjW -----END PGP SIGNATURE----- Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf Daniel Borkmann says: ==================== pull-request: bpf 2023-11-08 We've added 16 non-merge commits during the last 6 day(s) which contain a total of 30 files changed, 341 insertions(+), 130 deletions(-). The main changes are: 1) Fix a BPF verifier issue in precision tracking for BPF_ALU | BPF_TO_BE | BPF_END where the source register was incorrectly marked as precise, from Shung-Hsi Yu. 2) Fix a concurrency issue in bpf_timer where the former could still have been alive after an application releases or unpins the map, from Hou Tao. 3) Fix a BPF verifier issue where immediates are incorrectly cast to u32 before being spilled and therefore losing sign information, from Hao Sun. 4) Fix a misplaced BPF_TRACE_ITER in check_css_task_iter_allowlist which incorrectly compared bpf_prog_type with bpf_attach_type, from Chuyi Zhou. 5) Add __bpf_hook_{start,end} as well as __bpf_kfunc_{start,end}_defs macros, migrate all BPF-related __diag callsites over to it, and add a new __diag_ignore_all for -Wmissing-declarations to the macros to address recent build warnings, from Dave Marchevsky. 6) Fix broken BPF selftest build of xdp_hw_metadata test on architectures where char is not signed, from Björn Töpel. 7) Fix test_maps selftest to properly use LIBBPF_OPTS() macro to initialize the bpf_map_create_opts, from Andrii Nakryiko. 8) Fix bpffs selftest to avoid unmounting /sys/kernel/debug as it may have been mounted and used by other applications already, from Manu Bretelle. 9) Fix a build issue without CONFIG_CGROUPS wrt css_task open-coded iterators, from Matthieu Baerts. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: selftests/bpf: get trusted cgrp from bpf_iter__cgroup directly bpf: Let verifier consider {task,cgroup} is trusted in bpf_iter_reg selftests/bpf: Fix broken build where char is unsigned selftests/bpf: precision tracking test for BPF_NEG and BPF_END bpf: Fix precision tracking for BPF_ALU | BPF_TO_BE | BPF_END selftests/bpf: Add test for using css_task iter in sleepable progs selftests/bpf: Add tests for css_task iter combining with cgroup iter bpf: Relax allowlist for css_task iter selftests/bpf: fix test_maps' use of bpf_map_create_opts bpf: Check map->usercnt after timer->timer is assigned bpf: Add __bpf_hook_{start,end} macros bpf: Add __bpf_kfunc_{start,end}_defs macros selftests/bpf: fix test_bpffs selftests/bpf: Add test for immediate spilled to stack bpf: Fix check_stack_write_fixed_off() to correctly spill imm bpf: fix compilation error without CGROUPS ==================== Link: https://lore.kernel.org/r/20231108132448.1970-1-daniel@iogearbox.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
942b8b38de
30 changed files with 341 additions and 130 deletions
|
|
@ -39,9 +39,7 @@ struct bpf_testmod_struct_arg_4 {
|
|||
int b;
|
||||
};
|
||||
|
||||
__diag_push();
|
||||
__diag_ignore_all("-Wmissing-prototypes",
|
||||
"Global functions as their definitions will be in bpf_testmod.ko BTF");
|
||||
__bpf_hook_start();
|
||||
|
||||
noinline int
|
||||
bpf_testmod_test_struct_arg_1(struct bpf_testmod_struct_arg_2 a, int b, int c) {
|
||||
|
|
@ -335,7 +333,7 @@ noinline int bpf_fentry_shadow_test(int a)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(bpf_fentry_shadow_test);
|
||||
|
||||
__diag_pop();
|
||||
__bpf_hook_end();
|
||||
|
||||
static struct bin_attribute bin_attr_bpf_testmod_file __ro_after_init = {
|
||||
.attr = { .name = "bpf_testmod", .mode = 0666, },
|
||||
|
|
|
|||
|
|
@ -326,20 +326,14 @@ static int map_create(__u32 type, const char *name, struct bpf_map_create_opts *
|
|||
|
||||
static int create_hash(void)
|
||||
{
|
||||
struct bpf_map_create_opts map_opts = {
|
||||
.sz = sizeof(map_opts),
|
||||
.map_flags = BPF_F_NO_PREALLOC,
|
||||
};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts, .map_flags = BPF_F_NO_PREALLOC);
|
||||
|
||||
return map_create(BPF_MAP_TYPE_HASH, "hash", &map_opts);
|
||||
}
|
||||
|
||||
static int create_percpu_hash(void)
|
||||
{
|
||||
struct bpf_map_create_opts map_opts = {
|
||||
.sz = sizeof(map_opts),
|
||||
.map_flags = BPF_F_NO_PREALLOC,
|
||||
};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts, .map_flags = BPF_F_NO_PREALLOC);
|
||||
|
||||
return map_create(BPF_MAP_TYPE_PERCPU_HASH, "percpu_hash", &map_opts);
|
||||
}
|
||||
|
|
@ -356,21 +350,17 @@ static int create_percpu_hash_prealloc(void)
|
|||
|
||||
static int create_lru_hash(__u32 type, __u32 map_flags)
|
||||
{
|
||||
struct bpf_map_create_opts map_opts = {
|
||||
.sz = sizeof(map_opts),
|
||||
.map_flags = map_flags,
|
||||
};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts, .map_flags = map_flags);
|
||||
|
||||
return map_create(type, "lru_hash", &map_opts);
|
||||
}
|
||||
|
||||
static int create_hash_of_maps(void)
|
||||
{
|
||||
struct bpf_map_create_opts map_opts = {
|
||||
.sz = sizeof(map_opts),
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts,
|
||||
.map_flags = BPF_F_NO_PREALLOC,
|
||||
.inner_map_fd = create_small_hash(),
|
||||
};
|
||||
);
|
||||
int ret;
|
||||
|
||||
ret = map_create_opts(BPF_MAP_TYPE_HASH_OF_MAPS, "hash_of_maps",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <test_progs.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include <bpf/btf.h>
|
||||
#include "iters_css_task.skel.h"
|
||||
#include "cgroup_iter.skel.h"
|
||||
#include "cgroup_helpers.h"
|
||||
|
||||
|
|
@ -263,6 +264,35 @@ close_cgrp:
|
|||
close(cgrp_fd);
|
||||
}
|
||||
|
||||
static void test_walk_self_only_css_task(void)
|
||||
{
|
||||
struct iters_css_task *skel;
|
||||
int err;
|
||||
|
||||
skel = iters_css_task__open();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open"))
|
||||
return;
|
||||
|
||||
bpf_program__set_autoload(skel->progs.cgroup_id_printer, true);
|
||||
|
||||
err = iters_css_task__load(skel);
|
||||
if (!ASSERT_OK(err, "skel_load"))
|
||||
goto cleanup;
|
||||
|
||||
err = join_cgroup(cg_path[CHILD2]);
|
||||
if (!ASSERT_OK(err, "join_cgroup"))
|
||||
goto cleanup;
|
||||
|
||||
skel->bss->target_pid = getpid();
|
||||
snprintf(expected_output, sizeof(expected_output),
|
||||
PROLOGUE "%8llu\n" EPILOGUE, cg_id[CHILD2]);
|
||||
read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[CHILD2],
|
||||
BPF_CGROUP_ITER_SELF_ONLY, "test_walk_self_only_css_task");
|
||||
ASSERT_EQ(skel->bss->css_task_cnt, 1, "css_task_cnt");
|
||||
cleanup:
|
||||
iters_css_task__destroy(skel);
|
||||
}
|
||||
|
||||
void test_cgroup_iter(void)
|
||||
{
|
||||
struct cgroup_iter *skel = NULL;
|
||||
|
|
@ -293,6 +323,9 @@ void test_cgroup_iter(void)
|
|||
test_walk_self_only(skel);
|
||||
if (test__start_subtest("cgroup_iter__dead_self_only"))
|
||||
test_walk_dead_self_only(skel);
|
||||
if (test__start_subtest("cgroup_iter__self_only_css_task"))
|
||||
test_walk_self_only_css_task();
|
||||
|
||||
out:
|
||||
cgroup_iter__destroy(skel);
|
||||
cleanup_cgroups();
|
||||
|
|
|
|||
|
|
@ -294,6 +294,7 @@ void test_iters(void)
|
|||
RUN_TESTS(iters_state_safety);
|
||||
RUN_TESTS(iters_looping);
|
||||
RUN_TESTS(iters);
|
||||
RUN_TESTS(iters_css_task);
|
||||
|
||||
if (env.has_testmod)
|
||||
RUN_TESTS(iters_testmod_seq);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <test_progs.h>
|
||||
|
||||
#define TDIR "/sys/kernel/debug"
|
||||
/* TDIR must be in a location we can create a directory in. */
|
||||
#define TDIR "/tmp/test_bpffs_testdir"
|
||||
|
||||
static int read_iter(char *file)
|
||||
{
|
||||
|
|
@ -43,8 +44,11 @@ static int fn(void)
|
|||
if (!ASSERT_OK(err, "mount /"))
|
||||
goto out;
|
||||
|
||||
err = umount(TDIR);
|
||||
if (!ASSERT_OK(err, "umount " TDIR))
|
||||
err = mkdir(TDIR, 0777);
|
||||
/* If the directory already exists we can carry on. It may be left over
|
||||
* from a previous run.
|
||||
*/
|
||||
if ((err && errno != EEXIST) && !ASSERT_OK(err, "mkdir " TDIR))
|
||||
goto out;
|
||||
|
||||
err = mount("none", TDIR, "tmpfs", 0, NULL);
|
||||
|
|
@ -138,6 +142,7 @@ out:
|
|||
rmdir(TDIR "/fs1");
|
||||
rmdir(TDIR "/fs2");
|
||||
umount(TDIR);
|
||||
rmdir(TDIR);
|
||||
exit(err);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include "verifier_movsx.skel.h"
|
||||
#include "verifier_netfilter_ctx.skel.h"
|
||||
#include "verifier_netfilter_retcode.skel.h"
|
||||
#include "verifier_precision.skel.h"
|
||||
#include "verifier_prevent_map_lookup.skel.h"
|
||||
#include "verifier_raw_stack.skel.h"
|
||||
#include "verifier_raw_tp_writable.skel.h"
|
||||
|
|
@ -153,6 +154,7 @@ void test_verifier_meta_access(void) { RUN(verifier_meta_access); }
|
|||
void test_verifier_movsx(void) { RUN(verifier_movsx); }
|
||||
void test_verifier_netfilter_ctx(void) { RUN(verifier_netfilter_ctx); }
|
||||
void test_verifier_netfilter_retcode(void) { RUN(verifier_netfilter_retcode); }
|
||||
void test_verifier_precision(void) { RUN(verifier_precision); }
|
||||
void test_verifier_prevent_map_lookup(void) { RUN(verifier_prevent_map_lookup); }
|
||||
void test_verifier_raw_stack(void) { RUN(verifier_raw_stack); }
|
||||
void test_verifier_raw_tp_writable(void) { RUN(verifier_raw_tp_writable); }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
struct cgroup *bpf_cgroup_acquire(struct cgroup *p) __ksym;
|
||||
struct cgroup *bpf_cgroup_from_id(u64 cgid) __ksym;
|
||||
void bpf_cgroup_release(struct cgroup *p) __ksym;
|
||||
|
||||
|
|
@ -45,3 +46,57 @@ int BPF_PROG(iter_css_task_for_each, struct vm_area_struct *vma,
|
|||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static inline u64 cgroup_id(struct cgroup *cgrp)
|
||||
{
|
||||
return cgrp->kn->id;
|
||||
}
|
||||
|
||||
SEC("?iter/cgroup")
|
||||
int cgroup_id_printer(struct bpf_iter__cgroup *ctx)
|
||||
{
|
||||
struct seq_file *seq = ctx->meta->seq;
|
||||
struct cgroup *cgrp = ctx->cgroup;
|
||||
struct cgroup_subsys_state *css;
|
||||
struct task_struct *task;
|
||||
|
||||
/* epilogue */
|
||||
if (cgrp == NULL) {
|
||||
BPF_SEQ_PRINTF(seq, "epilogue\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prologue */
|
||||
if (ctx->meta->seq_num == 0)
|
||||
BPF_SEQ_PRINTF(seq, "prologue\n");
|
||||
|
||||
BPF_SEQ_PRINTF(seq, "%8llu\n", cgroup_id(cgrp));
|
||||
|
||||
css = &cgrp->self;
|
||||
css_task_cnt = 0;
|
||||
bpf_for_each(css_task, task, css, CSS_TASK_ITER_PROCS) {
|
||||
if (task->pid == target_pid)
|
||||
css_task_cnt++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
|
||||
int BPF_PROG(iter_css_task_for_each_sleep)
|
||||
{
|
||||
u64 cgrp_id = bpf_get_current_cgroup_id();
|
||||
struct cgroup *cgrp = bpf_cgroup_from_id(cgrp_id);
|
||||
struct cgroup_subsys_state *css;
|
||||
struct task_struct *task;
|
||||
|
||||
if (cgrp == NULL)
|
||||
return 0;
|
||||
css = &cgrp->self;
|
||||
|
||||
bpf_for_each(css_task, task, css, CSS_TASK_ITER_PROCS) {
|
||||
|
||||
}
|
||||
bpf_cgroup_release(cgrp);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ int BPF_PROG(iter_css_lock_and_unlock)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
|
||||
__failure __msg("css_task_iter is only allowed in bpf_lsm and bpf iter-s")
|
||||
SEC("?fentry/" SYS_PREFIX "sys_getpgid")
|
||||
__failure __msg("css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs")
|
||||
int BPF_PROG(iter_css_task_for_each)
|
||||
{
|
||||
u64 cg_id = bpf_get_current_cgroup_id();
|
||||
|
|
|
|||
93
tools/testing/selftests/bpf/progs/verifier_precision.c
Normal file
93
tools/testing/selftests/bpf/progs/verifier_precision.c
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (C) 2023 SUSE LLC */
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf_misc.h"
|
||||
|
||||
SEC("?raw_tp")
|
||||
__success __log_level(2)
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 3: (bf) r1 = r10")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 2: (55) if r2 != 0xfffffff8 goto pc+2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 1: (87) r2 = -r2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 0: (b7) r2 = 8")
|
||||
__naked int bpf_neg(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r2 = 8;"
|
||||
"r2 = -r2;"
|
||||
"if r2 != -8 goto 1f;"
|
||||
"r1 = r10;"
|
||||
"r1 += r2;"
|
||||
"1:"
|
||||
"r0 = 0;"
|
||||
"exit;"
|
||||
::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("?raw_tp")
|
||||
__success __log_level(2)
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 3: (bf) r1 = r10")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 2: (55) if r2 != 0x0 goto pc+2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 1: (d4) r2 = le16 r2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 0: (b7) r2 = 0")
|
||||
__naked int bpf_end_to_le(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r2 = 0;"
|
||||
"r2 = le16 r2;"
|
||||
"if r2 != 0 goto 1f;"
|
||||
"r1 = r10;"
|
||||
"r1 += r2;"
|
||||
"1:"
|
||||
"r0 = 0;"
|
||||
"exit;"
|
||||
::: __clobber_all);
|
||||
}
|
||||
|
||||
|
||||
SEC("?raw_tp")
|
||||
__success __log_level(2)
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 3: (bf) r1 = r10")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 2: (55) if r2 != 0x0 goto pc+2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 1: (dc) r2 = be16 r2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 0: (b7) r2 = 0")
|
||||
__naked int bpf_end_to_be(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r2 = 0;"
|
||||
"r2 = be16 r2;"
|
||||
"if r2 != 0 goto 1f;"
|
||||
"r1 = r10;"
|
||||
"r1 += r2;"
|
||||
"1:"
|
||||
"r0 = 0;"
|
||||
"exit;"
|
||||
::: __clobber_all);
|
||||
}
|
||||
|
||||
#if (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \
|
||||
(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64) || \
|
||||
defined(__TARGET_ARCH_arm) || defined(__TARGET_ARCH_s390)) && \
|
||||
__clang_major__ >= 18
|
||||
|
||||
SEC("?raw_tp")
|
||||
__success __log_level(2)
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 3: (bf) r1 = r10")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 2: (55) if r2 != 0x0 goto pc+2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 1: (d7) r2 = bswap16 r2")
|
||||
__msg("mark_precise: frame0: regs=r2 stack= before 0: (b7) r2 = 0")
|
||||
__naked int bpf_end_bswap(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r2 = 0;"
|
||||
"r2 = bswap16 r2;"
|
||||
"if r2 != 0 goto 1f;"
|
||||
"r1 = r10;"
|
||||
"r1 += r2;"
|
||||
"1:"
|
||||
"r0 = 0;"
|
||||
"exit;"
|
||||
::: __clobber_all);
|
||||
}
|
||||
|
||||
#endif /* v4 instruction */
|
||||
|
|
@ -65,3 +65,35 @@
|
|||
.expected_attach_type = BPF_SK_LOOKUP,
|
||||
.runs = -1,
|
||||
},
|
||||
{
|
||||
"BPF_ST_MEM stack imm sign",
|
||||
/* Check if verifier correctly reasons about sign of an
|
||||
* immediate spilled to stack by BPF_ST instruction.
|
||||
*
|
||||
* fp[-8] = -44;
|
||||
* r0 = fp[-8];
|
||||
* if r0 s< 0 goto ret0;
|
||||
* r0 = -1;
|
||||
* exit;
|
||||
* ret0:
|
||||
* r0 = 0;
|
||||
* exit;
|
||||
*/
|
||||
.insns = {
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, -44),
|
||||
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8),
|
||||
BPF_JMP_IMM(BPF_JSLT, BPF_REG_0, 0, 2),
|
||||
BPF_MOV64_IMM(BPF_REG_0, -1),
|
||||
BPF_EXIT_INSN(),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
/* Use prog type that requires return value in range [0, 1] */
|
||||
.prog_type = BPF_PROG_TYPE_SK_LOOKUP,
|
||||
.expected_attach_type = BPF_SK_LOOKUP,
|
||||
.result = VERBOSE_ACCEPT,
|
||||
.runs = -1,
|
||||
.errstr = "0: (7a) *(u64 *)(r10 -8) = -44 ; R10=fp0 fp-8_w=-44\
|
||||
2: (c5) if r0 s< 0x0 goto pc+2\
|
||||
R0_w=-44",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ static void print_usage(void)
|
|||
|
||||
static void read_args(int argc, char *argv[])
|
||||
{
|
||||
char opt;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "mh")) != -1) {
|
||||
switch (opt) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue