mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
selftests/bpf: Cover helper memory access permissions
Check that fixed-size and sized helper input/output buffers require both read and write permission. Cover the MTU and FIB helpers, including read-only and write-only rejection and read/write positive controls. Exercise the XDP prototypes and the sock_ops header-option input/output argument as well. Keep write-only maps usable as destinations for partial-output helpers bpf_snprintf() and bpf_sysctl_get_name(), while rejecting a read-only snprintf destination. Also retain a write-only-map destination for bpf_get_current_comm(), whose output is annotated MEM_UNINIT and fully initialized by the helper. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20260921023843.411943-12-memxor@gmail.com
This commit is contained in:
parent
7a6cef39b7
commit
ad36589c3f
|
|
@ -1,4 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
|
||||
/* Converted from tools/testing/selftests/bpf/verifier/helper_access_var_len.c */
|
||||
|
||||
#include <linux/bpf.h>
|
||||
|
|
@ -822,6 +823,148 @@ __naked void bytes_no_leak_init_memory(void)
|
|||
: __clobber_all);
|
||||
}
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(map_flags, BPF_F_WRONLY_PROG);
|
||||
__type(key, __u32);
|
||||
__type(value, struct bpf_fib_lookup);
|
||||
} map_fib_wo SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, struct bpf_fib_lookup);
|
||||
} map_fib_rw SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(map_flags, BPF_F_RDONLY_PROG);
|
||||
__type(key, __u32);
|
||||
__type(value, struct bpf_fib_lookup);
|
||||
} map_fib_ro SEC(".maps");
|
||||
|
||||
SEC("tc")
|
||||
__failure __msg("read from map forbidden")
|
||||
int writeonly_sized_input(struct __sk_buff *ctx)
|
||||
{
|
||||
struct bpf_fib_lookup *params;
|
||||
__u32 key = 0;
|
||||
|
||||
params = bpf_map_lookup_elem(&map_fib_wo, &key);
|
||||
if (params)
|
||||
bpf_fib_lookup(ctx, params, sizeof(*params), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
__success
|
||||
int readwrite_sized_input(struct __sk_buff *ctx)
|
||||
{
|
||||
struct bpf_fib_lookup *params;
|
||||
__u32 key = 0;
|
||||
|
||||
params = bpf_map_lookup_elem(&map_fib_rw, &key);
|
||||
if (params)
|
||||
bpf_fib_lookup(ctx, params, sizeof(*params), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
__failure __msg("write into map forbidden")
|
||||
int readonly_sized_output(struct __sk_buff *ctx)
|
||||
{
|
||||
struct bpf_fib_lookup *params;
|
||||
__u32 key = 0;
|
||||
|
||||
params = bpf_map_lookup_elem(&map_fib_ro, &key);
|
||||
if (params)
|
||||
bpf_fib_lookup(ctx, params, sizeof(*params), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("xdp")
|
||||
__failure __msg("read from map forbidden")
|
||||
int xdp_writeonly_sized_input(struct xdp_md *ctx)
|
||||
{
|
||||
struct bpf_fib_lookup *params;
|
||||
__u32 key = 0;
|
||||
|
||||
params = bpf_map_lookup_elem(&map_fib_wo, &key);
|
||||
if (params)
|
||||
bpf_fib_lookup(ctx, params, sizeof(*params), 0);
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
SEC("sockops")
|
||||
__failure __msg("read from map forbidden")
|
||||
int writeonly_header_option(struct bpf_sock_ops *ctx)
|
||||
{
|
||||
struct bpf_fib_lookup *buf;
|
||||
__u32 key = 0;
|
||||
|
||||
buf = bpf_map_lookup_elem(&map_fib_wo, &key);
|
||||
if (buf)
|
||||
bpf_load_hdr_opt(ctx, buf, sizeof(*buf), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("sockops")
|
||||
__success
|
||||
int readwrite_header_option(struct bpf_sock_ops *ctx)
|
||||
{
|
||||
struct bpf_fib_lookup *buf;
|
||||
__u32 key = 0;
|
||||
|
||||
buf = bpf_map_lookup_elem(&map_fib_rw, &key);
|
||||
if (buf)
|
||||
bpf_load_hdr_opt(ctx, buf, sizeof(*buf), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
__success
|
||||
int snprintf_writeonly_output(struct __sk_buff *ctx)
|
||||
{
|
||||
void *buf;
|
||||
__u32 key = 0;
|
||||
|
||||
buf = bpf_map_lookup_elem(&map_fib_wo, &key);
|
||||
if (buf)
|
||||
bpf_snprintf(buf, 16, "ok", NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
__failure __msg("write into map forbidden")
|
||||
int snprintf_readonly_output(struct __sk_buff *ctx)
|
||||
{
|
||||
void *buf;
|
||||
__u32 key = 0;
|
||||
|
||||
buf = bpf_map_lookup_elem(&map_fib_ro, &key);
|
||||
if (buf)
|
||||
bpf_snprintf(buf, 16, "ok", NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("cgroup/sysctl")
|
||||
__success
|
||||
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
|
||||
__success_unpriv
|
||||
int sysctl_writeonly_output(struct bpf_sysctl *ctx)
|
||||
{
|
||||
void *buf;
|
||||
__u32 key = 0;
|
||||
|
||||
buf = bpf_map_lookup_elem(&map_fib_wo, &key);
|
||||
if (buf)
|
||||
bpf_sysctl_get_name(ctx, buf, 16, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("cgroup/sysctl")
|
||||
__success
|
||||
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
|
||||
|
|
|
|||
|
|
@ -17,4 +17,92 @@ int tc_uninit_mtu(struct __sk_buff *ctx)
|
|||
return TCX_PASS;
|
||||
}
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(map_flags, BPF_F_WRONLY_PROG);
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} map_mtu_wo SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} map_mtu_rw SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(map_flags, BPF_F_RDONLY_PROG);
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} map_mtu_ro SEC(".maps");
|
||||
|
||||
SEC("tc/ingress")
|
||||
__failure __msg("read from map forbidden")
|
||||
int tc_writeonly_mtu(struct __sk_buff *ctx)
|
||||
{
|
||||
__u32 key = 0;
|
||||
__u32 *mtu;
|
||||
|
||||
mtu = bpf_map_lookup_elem(&map_mtu_wo, &key);
|
||||
if (mtu)
|
||||
bpf_check_mtu(ctx, 0, mtu, 0, 0);
|
||||
return TCX_PASS;
|
||||
}
|
||||
|
||||
SEC("tc/ingress")
|
||||
__success
|
||||
int tc_readwrite_mtu(struct __sk_buff *ctx)
|
||||
{
|
||||
__u32 key = 0;
|
||||
__u32 *mtu;
|
||||
|
||||
mtu = bpf_map_lookup_elem(&map_mtu_rw, &key);
|
||||
if (mtu)
|
||||
bpf_check_mtu(ctx, 0, mtu, 0, 0);
|
||||
return TCX_PASS;
|
||||
}
|
||||
|
||||
SEC("xdp")
|
||||
__failure __msg("read from map forbidden")
|
||||
int xdp_writeonly_mtu(struct xdp_md *ctx)
|
||||
{
|
||||
__u32 key = 0;
|
||||
__u32 *mtu;
|
||||
|
||||
mtu = bpf_map_lookup_elem(&map_mtu_wo, &key);
|
||||
if (mtu)
|
||||
bpf_check_mtu(ctx, 0, mtu, 0, 0);
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
SEC("tc/ingress")
|
||||
__failure __msg("write into map forbidden")
|
||||
int tc_readonly_mtu(struct __sk_buff *ctx)
|
||||
{
|
||||
__u32 key = 0;
|
||||
__u32 *mtu;
|
||||
|
||||
mtu = bpf_map_lookup_elem(&map_mtu_ro, &key);
|
||||
if (mtu)
|
||||
bpf_check_mtu(ctx, 0, mtu, 0, 0);
|
||||
return TCX_PASS;
|
||||
}
|
||||
|
||||
SEC("tc/ingress")
|
||||
__success
|
||||
int tc_writeonly_output(struct __sk_buff *ctx)
|
||||
{
|
||||
__u32 key = 0;
|
||||
__u32 *out;
|
||||
|
||||
out = bpf_map_lookup_elem(&map_mtu_wo, &key);
|
||||
if (out)
|
||||
bpf_get_current_comm(out, sizeof(*out));
|
||||
return TCX_PASS;
|
||||
}
|
||||
|
||||
char LICENSE[] SEC("license") = "GPL";
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user