bpf: enforce that struct_ops programs be GPL-only
Subsystems (6)
PATCH v3 1/2 bpf: enforce that struct_ops programs be GPL-only
With the introduction of the struct_ops program type, it became possible to implement kernel functionality in BPF, making it viable to use BPF in place of a regular kernel module for these particular operations.
Thus far, the only user of this mechanism is for implementing TCP congestion control algorithms. These are clearly marked as GPL-only when implemented as modules (as seen by the use of EXPORT_SYMBOL_GPL for tcp_register_congestion_control()), so it seems like an oversight that this was not carried over to BPF implementations. Since this is the only user of the struct_ops mechanism, just enforcing GPL-only for the struct_ops program type seems like the simplest way to fix this.
v3: No change
v2: Move check to the top of check_struct_ops_btf_id().
--- kernel/bpf/verifier.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/bpf/verifier.c +5 -0
@@ -12158,6 +12158,11 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)u32 btf_id, member_idx;const char *mname; +if (!prog->gpl_compatible) { +verbose (env,"struct ops programs must have a GPL compatible license\n" ); +return -EINVAL ; + } + btf_id = prog->aux->attach_btf_id; st_ops =bpf_struct_ops_find (btf_id);if (!st_ops) {
Signature · 1 line
2.31.0
PATCH v3 2/2 bpf/selftests: test that kernel rejects a TCP CC with an invalid license
This adds a selftest to check that the verifier rejects a TCP CC struct_ops with a non-GPL license.
v3:
- Rename prog to bpf_tcp_nogpl
- Use ASSERT macros instead of CHECK
- Skip unneeded initialisation, unconditionally close skeleton v2:
- Use a minimal struct_ops BPF program instead of rewriting bpf_dctcp's license in memory.
- Check for the verifier reject message instead of just the return code.
--- .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 44 +++++++++++++++++++ .../selftests/bpf/progs/bpf_tcp_nogpl.c | 19 ++++++++ 2 files changed, 63 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/bpf_tcp_nogpl.c
tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c +44 -0
@@ -6,6 +6,7 @@#include <test_progs.h> #include "bpf_dctcp.skel.h" #include "bpf_cubic.skel.h" +#include "bpf_tcp_nogpl.skel.h" #define min (a, b) ((a) < (b) ? (a) : (b))
@@ -227,10 +228,53 @@ static void test_dctcp(void)bpf_dctcp__destroy (dctcp_skel); } +static char *err_str; +static bool found; + +static int libbpf_debug_print (enum libbpf_print_level level, +const char *format,va_list args) +{ +char *log_buf; + +if (level !=LIBBPF_WARN || +strcmp (format,"libbpf: \n%s\n" )) { +vprintf (format, args); +return 0 ; + } + + log_buf = va_arg(args, char *); +if (!log_buf) + goto out; +if (err_str &&strstr (log_buf, err_str) !=NULL ) + found = true; +out: +printf (format, log_buf); +return 0 ; +} + +static void test_invalid_license (void ) +{ +libbpf_print_fn_t old_print_fn; +struct bpf_tcp_nogpl *skel; + + err_str ="struct ops programs must have a GPL compatible license" ; + found = false; + old_print_fn =libbpf_set_print (libbpf_debug_print); + + skel =bpf_tcp_nogpl__open_and_load (); +ASSERT_NULL (skel,"bpf_tcp_nogpl" ); +ASSERT_EQ (found, true,"expected_err_msg" ); + +bpf_tcp_nogpl__destroy (skel); +libbpf_set_print (old_print_fn); +} +void test_bpf_tcp_ca (void ) {if (test__start_subtest ("dctcp" ))test_dctcp ();if (test__start_subtest ("cubic" ))test_cubic (); +if (test__start_subtest ("invalid_license" )) +test_invalid_license (); }
tools/testing/selftests/bpf/progs/bpf_tcp_nogpl.c new file +19 -0
@@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/bpf.h> +#include <linux/types.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include "bpf_tcp_helpers.h" + +char _license[] SEC("license") = "X"; + +void BPF_STRUCT_OPS (nogpltcp_init ,struct sock *sk) +{ +} + +SEC(".struct_ops") +struct tcp_congestion_ops bpf_nogpltcp = { + .init = (void *)nogpltcp_init, + .name ="bpf_nogpltcp" , +};
Signature · 1 line
2.31.0
This series was applied to bpf/bpf.git (refs/heads/master):
Hello:
This series was applied to bpf/bpf.git (refs/heads/master):
Quoted 12 lines · On Fri, 26 Mar 2021 11:03:13 +0100 you wrote:
With the introduction of the
struct_opsprogram type, it became possible to implement kernel functionality in BPF, making it viable to use BPF in place of a regular kernel module for these particular operations.Thus far, the only user of this mechanism is for implementing TCP congestion control algorithms. These are clearly marked as GPL-only when implemented as modules (as seen by the use of
EXPORT_SYMBOL_GPLfortcp_register_congestion_control()), so it seems like an oversight that this was not carried over to BPF implementations. Since this is the only user of thestruct_opsmechanism, just enforcing GPL-only for thestruct_opsprogram type seems like the simplest way to fix this.
Quoted 1 line
[...]
Here is the summary with links:
- [bpf,v3,1/2] bpf: enforce that struct_ops programs be GPL-only
https://git.kernel.org/bpf/bpf/c/12aa8a9467b3 - [bpf,v3,2/2] bpf/selftests: test that kernel rejects a TCP CC with an invalid license https://git.kernel.org/bpf/bpf/c/d8e8052e42d0
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html