Skip to content

Commit

Permalink
Merge branch 'Fix wrong cgroup attach flags being assigned to effecti…
Browse files Browse the repository at this point in the history
…ve progs'

Pu Lehui says:

====================

From: Pu Lehui <[email protected]>

When root-cgroup attach multi progs and sub-cgroup attach a
override prog, bpftool will display incorrectly for the attach
flags of the sub-cgroup’s effective progs:

$ bpftool cgroup tree /sys/fs/cgroup effective
CgroupPath
ID       AttachType      AttachFlags     Name
/sys/fs/cgroup
6        cgroup_sysctl   multi           sysctl_tcp_mem
13       cgroup_sysctl   multi           sysctl_tcp_mem
/sys/fs/cgroup/cg1
20       cgroup_sysctl   override        sysctl_tcp_mem
6        cgroup_sysctl   override        sysctl_tcp_mem <- wrong
13       cgroup_sysctl   override        sysctl_tcp_mem <- wrong
/sys/fs/cgroup/cg1/cg2
20       cgroup_sysctl                   sysctl_tcp_mem
6        cgroup_sysctl                   sysctl_tcp_mem
13       cgroup_sysctl                   sysctl_tcp_mem

For cg1, obviously, the attach flags of prog6 and prog13 can not be
OVERRIDE. And for query with EFFECTIVE flags, exporting attach flags
does not make sense. So let's remove the AttachFlags field and the
associated logic. After these patches, the above effective cgroup
tree will show as bellow:

# bpftool cgroup tree /sys/fs/cgroup effective
CgroupPath
ID       AttachType      Name
/sys/fs/cgroup
6        cgroup_sysctl   sysctl_tcp_mem
13       cgroup_sysctl   sysctl_tcp_mem
/sys/fs/cgroup/cg1
20       cgroup_sysctl   sysctl_tcp_mem
6        cgroup_sysctl   sysctl_tcp_mem
13       cgroup_sysctl   sysctl_tcp_mem
/sys/fs/cgroup/cg1/cg2
20       cgroup_sysctl   sysctl_tcp_mem
6        cgroup_sysctl   sysctl_tcp_mem
13       cgroup_sysctl   sysctl_tcp_mem

v5:
- Adapt selftests for effective query uapi change.

v4:
https://lore.kernel.org/bpf/[email protected]
- Reject prog_attach_flags array when effective query. (Martin)
- Target to bpf tree. (Martin)

v3:
https://lore.kernel.org/bpf/[email protected]
- Don't show attach flags when effective query. (John, sdf, Martin)

v2:
https://lore.kernel.org/bpf/[email protected]
- Limit prog_cnt to avoid overflow. (John)
- Add more detail message.

v1:
https://lore.kernel.org/bpf/[email protected]
====================

Signed-off-by: Martin KaFai Lau <[email protected]>
  • Loading branch information
Martin KaFai Lau committed Sep 21, 2022
2 parents 83c10cc + d2aa993 commit d703256
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 26 deletions.
7 changes: 5 additions & 2 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ enum {

/* Query effective (directly attached + inherited from ancestor cgroups)
* programs that will be executed for events within a cgroup.
* attach_flags with this flag are returned only for directly attached programs.
* attach_flags with this flag are always returned 0.
*/
#define BPF_F_QUERY_EFFECTIVE (1U << 0)

Expand Down Expand Up @@ -1432,7 +1432,10 @@ union bpf_attr {
__u32 attach_flags;
__aligned_u64 prog_ids;
__u32 prog_cnt;
__aligned_u64 prog_attach_flags; /* output: per-program attach_flags */
/* output: per-program attach_flags.
* not allowed to be set during effective query.
*/
__aligned_u64 prog_attach_flags;
} query;

struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */
Expand Down
28 changes: 18 additions & 10 deletions kernel/bpf/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
union bpf_attr __user *uattr)
{
__u32 __user *prog_attach_flags = u64_to_user_ptr(attr->query.prog_attach_flags);
bool effective_query = attr->query.query_flags & BPF_F_QUERY_EFFECTIVE;
__u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
enum bpf_attach_type type = attr->query.attach_type;
enum cgroup_bpf_attach_type from_atype, to_atype;
Expand All @@ -1029,8 +1030,12 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
int total_cnt = 0;
u32 flags;

if (effective_query && prog_attach_flags)
return -EINVAL;

if (type == BPF_LSM_CGROUP) {
if (attr->query.prog_cnt && prog_ids && !prog_attach_flags)
if (!effective_query && attr->query.prog_cnt &&
prog_ids && !prog_attach_flags)
return -EINVAL;

from_atype = CGROUP_LSM_START;
Expand All @@ -1045,7 +1050,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
}

for (atype = from_atype; atype <= to_atype; atype++) {
if (attr->query.query_flags & BPF_F_QUERY_EFFECTIVE) {
if (effective_query) {
effective = rcu_dereference_protected(cgrp->bpf.effective[atype],
lockdep_is_held(&cgroup_mutex));
total_cnt += bpf_prog_array_length(effective);
Expand All @@ -1054,6 +1059,8 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
}
}

/* always output uattr->query.attach_flags as 0 during effective query */
flags = effective_query ? 0 : flags;
if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
return -EFAULT;
if (copy_to_user(&uattr->query.prog_cnt, &total_cnt, sizeof(total_cnt)))
Expand All @@ -1068,7 +1075,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
}

for (atype = from_atype; atype <= to_atype && total_cnt; atype++) {
if (attr->query.query_flags & BPF_F_QUERY_EFFECTIVE) {
if (effective_query) {
effective = rcu_dereference_protected(cgrp->bpf.effective[atype],
lockdep_is_held(&cgroup_mutex));
cnt = min_t(int, bpf_prog_array_length(effective), total_cnt);
Expand All @@ -1090,15 +1097,16 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
if (++i == cnt)
break;
}
}

if (prog_attach_flags) {
flags = cgrp->bpf.flags[atype];
if (prog_attach_flags) {
flags = cgrp->bpf.flags[atype];

for (i = 0; i < cnt; i++)
if (copy_to_user(prog_attach_flags + i, &flags, sizeof(flags)))
return -EFAULT;
prog_attach_flags += cnt;
for (i = 0; i < cnt; i++)
if (copy_to_user(prog_attach_flags + i,
&flags, sizeof(flags)))
return -EFAULT;
prog_attach_flags += cnt;
}
}

prog_ids += cnt;
Expand Down
54 changes: 49 additions & 5 deletions tools/bpf/bpftool/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
jsonw_string_field(json_wtr, "attach_type", attach_type_str);
else
jsonw_uint_field(json_wtr, "attach_type", attach_type);
jsonw_string_field(json_wtr, "attach_flags",
attach_flags_str);
if (!(query_flags & BPF_F_QUERY_EFFECTIVE))
jsonw_string_field(json_wtr, "attach_flags", attach_flags_str);
jsonw_string_field(json_wtr, "name", prog_name);
if (attach_btf_name)
jsonw_string_field(json_wtr, "attach_btf_name", attach_btf_name);
Expand All @@ -150,7 +150,10 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
printf("%-15s", attach_type_str);
else
printf("type %-10u", attach_type);
printf(" %-15s %-15s", attach_flags_str, prog_name);
if (query_flags & BPF_F_QUERY_EFFECTIVE)
printf(" %-15s", prog_name);
else
printf(" %-15s %-15s", attach_flags_str, prog_name);
if (attach_btf_name)
printf(" %-15s", attach_btf_name);
else if (info.attach_btf_id)
Expand Down Expand Up @@ -195,6 +198,32 @@ static int cgroup_has_attached_progs(int cgroup_fd)

return no_prog ? 0 : 1;
}

static int show_effective_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
int level)
{
LIBBPF_OPTS(bpf_prog_query_opts, p);
__u32 prog_ids[1024] = {0};
__u32 iter;
int ret;

p.query_flags = query_flags;
p.prog_cnt = ARRAY_SIZE(prog_ids);
p.prog_ids = prog_ids;

ret = bpf_prog_query_opts(cgroup_fd, type, &p);
if (ret)
return ret;

if (p.prog_cnt == 0)
return 0;

for (iter = 0; iter < p.prog_cnt; iter++)
show_bpf_prog(prog_ids[iter], type, NULL, level);

return 0;
}

static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
int level)
{
Expand Down Expand Up @@ -245,6 +274,14 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
return 0;
}

static int show_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
int level)
{
return query_flags & BPF_F_QUERY_EFFECTIVE ?
show_effective_bpf_progs(cgroup_fd, type, level) :
show_attached_bpf_progs(cgroup_fd, type, level);
}

static int do_show(int argc, char **argv)
{
enum bpf_attach_type type;
Expand Down Expand Up @@ -292,6 +329,8 @@ static int do_show(int argc, char **argv)

if (json_output)
jsonw_start_array(json_wtr);
else if (query_flags & BPF_F_QUERY_EFFECTIVE)
printf("%-8s %-15s %-15s\n", "ID", "AttachType", "Name");
else
printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
"AttachFlags", "Name");
Expand All @@ -304,7 +343,7 @@ static int do_show(int argc, char **argv)
* If we were able to get the show for at least one
* attach type, let's return 0.
*/
if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0)
if (show_bpf_progs(cgroup_fd, type, 0) == 0)
ret = 0;
}

Expand Down Expand Up @@ -362,7 +401,7 @@ static int do_show_tree_fn(const char *fpath, const struct stat *sb,

btf_vmlinux = libbpf_find_kernel_btf();
for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++)
show_attached_bpf_progs(cgroup_fd, type, ftw->level);
show_bpf_progs(cgroup_fd, type, ftw->level);

if (errno == EINVAL)
/* Last attach type does not support query.
Expand Down Expand Up @@ -436,6 +475,11 @@ static int do_show_tree(int argc, char **argv)

if (json_output)
jsonw_start_array(json_wtr);
else if (query_flags & BPF_F_QUERY_EFFECTIVE)
printf("%s\n"
"%-8s %-15s %-15s\n",
"CgroupPath",
"ID", "AttachType", "Name");
else
printf("%s\n"
"%-8s %-15s %-15s %-15s\n",
Expand Down
7 changes: 5 additions & 2 deletions tools/include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ enum {

/* Query effective (directly attached + inherited from ancestor cgroups)
* programs that will be executed for events within a cgroup.
* attach_flags with this flag are returned only for directly attached programs.
* attach_flags with this flag are always returned 0.
*/
#define BPF_F_QUERY_EFFECTIVE (1U << 0)

Expand Down Expand Up @@ -1432,7 +1432,10 @@ union bpf_attr {
__u32 attach_flags;
__aligned_u64 prog_ids;
__u32 prog_cnt;
__aligned_u64 prog_attach_flags; /* output: per-program attach_flags */
/* output: per-program attach_flags.
* not allowed to be set during effective query.
*/
__aligned_u64 prog_attach_flags;
} query;

struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */
Expand Down
11 changes: 4 additions & 7 deletions tools/testing/selftests/bpf/prog_tests/cgroup_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,9 @@ void serial_test_cgroup_link(void)

ping_and_check(cg_nr, 0);

/* query the number of effective progs and attach flags in root cg */
/* query the number of attached progs and attach flags in root cg */
err = bpf_prog_query(cgs[0].fd, BPF_CGROUP_INET_EGRESS,
BPF_F_QUERY_EFFECTIVE, &attach_flags, NULL,
&prog_cnt);
0, &attach_flags, NULL, &prog_cnt);
CHECK_FAIL(err);
CHECK_FAIL(attach_flags != BPF_F_ALLOW_MULTI);
if (CHECK(prog_cnt != 1, "effect_cnt", "exp %d, got %d\n", 1, prog_cnt))
Expand All @@ -85,17 +84,15 @@ void serial_test_cgroup_link(void)
BPF_F_QUERY_EFFECTIVE, NULL, NULL,
&prog_cnt);
CHECK_FAIL(err);
CHECK_FAIL(attach_flags != BPF_F_ALLOW_MULTI);
if (CHECK(prog_cnt != cg_nr, "effect_cnt", "exp %d, got %d\n",
cg_nr, prog_cnt))
goto cleanup;

/* query the effective prog IDs in last cg */
err = bpf_prog_query(cgs[last_cg].fd, BPF_CGROUP_INET_EGRESS,
BPF_F_QUERY_EFFECTIVE, &attach_flags,
prog_ids, &prog_cnt);
BPF_F_QUERY_EFFECTIVE, NULL, prog_ids,
&prog_cnt);
CHECK_FAIL(err);
CHECK_FAIL(attach_flags != BPF_F_ALLOW_MULTI);
if (CHECK(prog_cnt != cg_nr, "effect_cnt", "exp %d, got %d\n",
cg_nr, prog_cnt))
goto cleanup;
Expand Down

0 comments on commit d703256

Please sign in to comment.