Skip to content

Commit

Permalink
bpf: Add sleepable prog tests for cgrp local storage
Browse files Browse the repository at this point in the history
Add three tests for cgrp local storage support for sleepable progs.
Two tests can load and run properly, one for cgroup_iter, another
for passing current->cgroups->dfl_cgrp to bpf_cgrp_storage_get()
helper. One test has bpf_rcu_read_lock() and failed to load.

Signed-off-by: Yonghong Song <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Alexei Starovoitov <[email protected]>
  • Loading branch information
yonghong-song authored and Alexei Starovoitov committed Dec 5, 2022
1 parent 2c40d97 commit 41d76c7
Showing 2 changed files with 174 additions and 0 deletions.
94 changes: 94 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
Original file line number Diff line number Diff line change
@@ -10,7 +10,9 @@
#include "cgrp_ls_recursion.skel.h"
#include "cgrp_ls_attach_cgroup.skel.h"
#include "cgrp_ls_negative.skel.h"
#include "cgrp_ls_sleepable.skel.h"
#include "network_helpers.h"
#include "cgroup_helpers.h"

struct socket_cookie {
__u64 cookie_key;
@@ -150,14 +152,100 @@ static void test_negative(void)
}
}

static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id)
{
DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
union bpf_iter_link_info linfo;
struct cgrp_ls_sleepable *skel;
struct bpf_link *link;
int err, iter_fd;
char buf[16];

skel = cgrp_ls_sleepable__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;

bpf_program__set_autoload(skel->progs.cgroup_iter, true);
err = cgrp_ls_sleepable__load(skel);
if (!ASSERT_OK(err, "skel_load"))
goto out;

memset(&linfo, 0, sizeof(linfo));
linfo.cgroup.cgroup_fd = cgroup_fd;
linfo.cgroup.order = BPF_CGROUP_ITER_SELF_ONLY;
opts.link_info = &linfo;
opts.link_info_len = sizeof(linfo);
link = bpf_program__attach_iter(skel->progs.cgroup_iter, &opts);
if (!ASSERT_OK_PTR(link, "attach_iter"))
goto out;

iter_fd = bpf_iter_create(bpf_link__fd(link));
if (!ASSERT_GE(iter_fd, 0, "iter_create"))
goto out;

/* trigger the program run */
(void)read(iter_fd, buf, sizeof(buf));

ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id");

close(iter_fd);
out:
cgrp_ls_sleepable__destroy(skel);
}

static void test_no_rcu_lock(__u64 cgroup_id)
{
struct cgrp_ls_sleepable *skel;
int err;

skel = cgrp_ls_sleepable__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;

skel->bss->target_pid = syscall(SYS_gettid);

bpf_program__set_autoload(skel->progs.no_rcu_lock, true);
err = cgrp_ls_sleepable__load(skel);
if (!ASSERT_OK(err, "skel_load"))
goto out;

err = cgrp_ls_sleepable__attach(skel);
if (!ASSERT_OK(err, "skel_attach"))
goto out;

syscall(SYS_getpgid);

ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id");
out:
cgrp_ls_sleepable__destroy(skel);
}

static void test_rcu_lock(void)
{
struct cgrp_ls_sleepable *skel;
int err;

skel = cgrp_ls_sleepable__open();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;

bpf_program__set_autoload(skel->progs.yes_rcu_lock, true);
err = cgrp_ls_sleepable__load(skel);
ASSERT_ERR(err, "skel_load");

cgrp_ls_sleepable__destroy(skel);
}

void test_cgrp_local_storage(void)
{
__u64 cgroup_id;
int cgroup_fd;

cgroup_fd = test__join_cgroup("/cgrp_local_storage");
if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /cgrp_local_storage"))
return;

cgroup_id = get_cgroup_id("/cgrp_local_storage");
if (test__start_subtest("tp_btf"))
test_tp_btf(cgroup_fd);
if (test__start_subtest("attach_cgroup"))
@@ -166,6 +254,12 @@ void test_cgrp_local_storage(void)
test_recursion(cgroup_fd);
if (test__start_subtest("negative"))
test_negative();
if (test__start_subtest("cgroup_iter_sleepable"))
test_cgroup_iter_sleepable(cgroup_fd, cgroup_id);
if (test__start_subtest("no_rcu_lock"))
test_no_rcu_lock(cgroup_id);
if (test__start_subtest("rcu_lock"))
test_rcu_lock();

close(cgroup_fd);
}
80 changes: 80 additions & 0 deletions tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */

#include "bpf_iter.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "bpf_misc.h"

char _license[] SEC("license") = "GPL";

struct {
__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, int);
__type(value, long);
} map_a SEC(".maps");

__u32 target_pid;
__u64 cgroup_id;

void bpf_rcu_read_lock(void) __ksym;
void bpf_rcu_read_unlock(void) __ksym;

SEC("?iter.s/cgroup")
int cgroup_iter(struct bpf_iter__cgroup *ctx)
{
struct seq_file *seq = ctx->meta->seq;
struct cgroup *cgrp = ctx->cgroup;
long *ptr;

if (cgrp == NULL)
return 0;

ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0,
BPF_LOCAL_STORAGE_GET_F_CREATE);
if (ptr)
cgroup_id = cgrp->kn->id;
return 0;
}

SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
int no_rcu_lock(void *ctx)
{
struct task_struct *task;
struct cgroup *cgrp;
long *ptr;

task = bpf_get_current_task_btf();
if (task->pid != target_pid)
return 0;

/* ptr_to_btf_id semantics. should work. */
cgrp = task->cgroups->dfl_cgrp;
ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0,
BPF_LOCAL_STORAGE_GET_F_CREATE);
if (ptr)
cgroup_id = cgrp->kn->id;
return 0;
}

SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
int yes_rcu_lock(void *ctx)
{
struct task_struct *task;
struct cgroup *cgrp;
long *ptr;

task = bpf_get_current_task_btf();
if (task->pid != target_pid)
return 0;

bpf_rcu_read_lock();
cgrp = task->cgroups->dfl_cgrp;
/* cgrp is untrusted and cannot pass to bpf_cgrp_storage_get() helper. */
ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
if (ptr)
cgroup_id = cgrp->kn->id;
bpf_rcu_read_unlock();
return 0;
}

0 comments on commit 41d76c7

Please sign in to comment.