History

bpf: lsm: Implement attach, detach and execution

JITed BPF programs are dynamically attached to the LSM hooks using BPF trampolines. The trampoline prologue generates code to handle conversion of the signature of the hook to the appropriate BPF context. The allocated trampoline programs are attached to the nop functions initialized as LSM hooks. BPF_PROG_TYPE_LSM programs must have a GPL compatible license and and need CAP_SYS_ADMIN (required for loading eBPF programs). Upon attachment: * A BPF fexit trampoline is used for LSM hooks with a void return type. * A BPF fmod_ret trampoline is used for LSM hooks which return an int. The attached programs can override the return value of the bpf LSM hook to indicate a MAC Policy decision.

KP Singh committed 6 years ago

Commit 9e4e01d1 parent 9d3fdea6 files · +116 −27Browse files

Unified · Split

6 files
  1. include/linux/bpf_lsm.h +11 −0
  2. kernel/bpf/bpf_lsm.c +23 −0
  3. kernel/bpf/btf.c +15 −1
  4. kernel/bpf/syscall.c +39 −18
  5. kernel/bpf/trampoline.c +13 −4
  6. kernel/bpf/verifier.c +15 −4
include/linux/bpf_lsm.h+11−0
@@ -17,6 +17,17 @@ · 16 unmodified lines
1717 #include <linux/lsm_hook_defs.h>
1818 #undef LSM_HOOK
1919
20+int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
21+ const struct bpf_prog *prog);
22+
23+#else /* !CONFIG_BPF_LSM */
24+
25+static inline int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
26+ const struct bpf_prog *prog)
27+{
28+ return -EOPNOTSUPP;
29+}
30+
2031 #endif /* CONFIG_BPF_LSM */
2132
2233 #endif /* _LINUX_BPF_LSM_H */
kernel/bpf/bpf_lsm.c+23−0
@@ -9,6 +9,8 @@ · 8 unmodified lines
99 #include <linux/btf.h>
1010 #include <linux/lsm_hooks.h>
1111 #include <linux/bpf_lsm.h>
12+#include <linux/kallsyms.h>
13+#include <linux/bpf_verifier.h>
1214
1315 /* For every LSM hook that allows attachment of BPF programs, declare a nop
1416 * function where a BPF program can be attached.
@@ -22,6 +24,27 @@ noinline RET bpf_lsm_##NAME(__VA_ARGS__) \ · 7 unmodified lines
2224 #include <linux/lsm_hook_defs.h>
2325 #undef LSM_HOOK
2426
27+#define BPF_LSM_SYM_PREFX "bpf_lsm_"
28+
29+int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog,
30+ const struct bpf_prog *prog)
31+{
32+ if (!prog->gpl_compatible) {
33+ bpf_log(vlog,
34+ "LSM programs must have a GPL compatible license\n");
35+ return -EINVAL;
36+ }
37+
38+ if (strncmp(BPF_LSM_SYM_PREFX, prog->aux->attach_func_name,
39+ sizeof(BPF_LSM_SYM_PREFX) - 1)) {
40+ bpf_log(vlog, "attach_btf_id %u points to wrong type name %s\n",
41+ prog->aux->attach_btf_id, prog->aux->attach_func_name);
42+ return -EINVAL;
43+ }
44+
45+ return 0;
46+}
47+
2548 const struct bpf_prog_ops lsm_prog_ops = {
2649 };
2750
kernel/bpf/btf.c+15−1
@@ -3710,7 +3710,21 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, · 3709 unmodified lines
37103710 }
37113711
37123712 if (arg == nr_args) {
3713− if (prog->expected_attach_type == BPF_TRACE_FEXIT) {
3713+ if (prog->expected_attach_type == BPF_TRACE_FEXIT ||
3714+ prog->expected_attach_type == BPF_LSM_MAC) {
3715+ /* When LSM programs are attached to void LSM hooks
3716+ * they use FEXIT trampolines and when attached to
3717+ * int LSM hooks, they use MODIFY_RETURN trampolines.
3718+ *
3719+ * While the LSM programs are BPF_MODIFY_RETURN-like
3720+ * the check:
3721+ *
3722+ * if (ret_type != 'int')
3723+ * return -EINVAL;
3724+ *
3725+ * is _not_ done here. This is still safe as LSM hooks
3726+ * have only void and int return types.
3727+ */
37143728 if (!t)
37153729 return true;
37163730 t = btf_type_by_id(btf, t->type);
kernel/bpf/syscall.c+39−18
@@ -25,6 +25,7 @@ · 24 unmodified lines
2525 #include <linux/nospec.h>
2626 #include <linux/audit.h>
2727 #include <uapi/linux/btf.h>
28+#include <linux/bpf_lsm.h>
2829
2930 #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \
3031 (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \
@@ -1935,6 +1936,7 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type, · 1904 unmodified lines
19351936
19361937 switch (prog_type) {
19371938 case BPF_PROG_TYPE_TRACING:
1939+ case BPF_PROG_TYPE_LSM:
19381940 case BPF_PROG_TYPE_STRUCT_OPS:
19391941 case BPF_PROG_TYPE_EXT:
19401942 break;
@@ -2366,10 +2368,28 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog) · 425 unmodified lines
23662368 struct file *link_file;
23672369 int link_fd, err;
23682370
2369− if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
2370− prog->expected_attach_type != BPF_TRACE_FEXIT &&
2371− prog->expected_attach_type != BPF_MODIFY_RETURN &&
2372− prog->type != BPF_PROG_TYPE_EXT) {
2371+ switch (prog->type) {
2372+ case BPF_PROG_TYPE_TRACING:
2373+ if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
2374+ prog->expected_attach_type != BPF_TRACE_FEXIT &&
2375+ prog->expected_attach_type != BPF_MODIFY_RETURN) {
2376+ err = -EINVAL;
2377+ goto out_put_prog;
2378+ }
2379+ break;
2380+ case BPF_PROG_TYPE_EXT:
2381+ if (prog->expected_attach_type != 0) {
2382+ err = -EINVAL;
2383+ goto out_put_prog;
2384+ }
2385+ break;
2386+ case BPF_PROG_TYPE_LSM:
2387+ if (prog->expected_attach_type != BPF_LSM_MAC) {
2388+ err = -EINVAL;
2389+ goto out_put_prog;
2390+ }
2391+ break;
2392+ default:
23732393 err = -EINVAL;
23742394 goto out_put_prog;
23752395 }
@@ -2448,16 +2468,10 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr) · 72 unmodified lines
24482468 if (IS_ERR(prog))
24492469 return PTR_ERR(prog);
24502470
2451− if (prog->type != BPF_PROG_TYPE_RAW_TRACEPOINT &&
2452− prog->type != BPF_PROG_TYPE_TRACING &&
2453− prog->type != BPF_PROG_TYPE_EXT &&
2454− prog->type != BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE) {
2455− err = -EINVAL;
2456− goto out_put_prog;
2457− }
2458−
2459− if (prog->type == BPF_PROG_TYPE_TRACING ||
2460− prog->type == BPF_PROG_TYPE_EXT) {
2471+ switch (prog->type) {
2472+ case BPF_PROG_TYPE_TRACING:
2473+ case BPF_PROG_TYPE_EXT:
2474+ case BPF_PROG_TYPE_LSM:
24612475 if (attr->raw_tracepoint.name) {
24622476 /* The attach point for this category of programs
24632477 * should be specified via btf_id during program load.
@@ -2465,11 +2479,14 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr) · 1 unmodified line
24652479 err = -EINVAL;
24662480 goto out_put_prog;
24672481 }
2468− if (prog->expected_attach_type == BPF_TRACE_RAW_TP)
2482+ if (prog->type == BPF_PROG_TYPE_TRACING &&
2483+ prog->expected_attach_type == BPF_TRACE_RAW_TP) {
24692484 tp_name = prog->aux->attach_func_name;
2470− else
2471− return bpf_tracing_prog_attach(prog);
2472− } else {
2485+ break;
2486+ }
2487+ return bpf_tracing_prog_attach(prog);
2488+ case BPF_PROG_TYPE_RAW_TRACEPOINT:
2489+ case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
24732490 if (strncpy_from_user(buf,
24742491 u64_to_user_ptr(attr->raw_tracepoint.name),
24752492 sizeof(buf) - 1) < 0) {
@@ -2478,6 +2495,10 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr) · 2 unmodified lines
24782495 }
24792496 buf[sizeof(buf) - 1] = 0;
24802497 tp_name = buf;
2498+ break;
2499+ default:
2500+ err = -EINVAL;
2501+ goto out_put_prog;
24812502 }
24822503
24832504 btp = bpf_get_raw_tracepoint(tp_name);
kernel/bpf/trampoline.c+13−4
@@ -6,6 +6,7 @@ · 5 unmodified lines
66 #include <linux/ftrace.h>
77 #include <linux/rbtree_latch.h>
88 #include <linux/perf_event.h>
9+#include <linux/btf.h>
910
1011 /* dummy _ops. The verifier will operate on target program's ops. */
1112 const struct bpf_verifier_ops bpf_extension_verifier_ops = {
@@ -233,15 +234,23 @@ out: · 221 unmodified lines
233234 return err;
234235 }
235236
236−static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(enum bpf_attach_type t)
237+static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)
237238 {
238− switch (t) {
239+ switch (prog->expected_attach_type) {
239240 case BPF_TRACE_FENTRY:
240241 return BPF_TRAMP_FENTRY;
241242 case BPF_MODIFY_RETURN:
242243 return BPF_TRAMP_MODIFY_RETURN;
243244 case BPF_TRACE_FEXIT:
244245 return BPF_TRAMP_FEXIT;
246+ case BPF_LSM_MAC:
247+ if (!prog->aux->attach_func_proto->type)
248+ /* The function returns void, we cannot modify its
249+ * return value.
250+ */
251+ return BPF_TRAMP_FEXIT;
252+ else
253+ return BPF_TRAMP_MODIFY_RETURN;
245254 default:
246255 return BPF_TRAMP_REPLACE;
247256 }
@@ -255,7 +264,7 @@ int bpf_trampoline_link_prog(struct bpf_prog *prog) · 7 unmodified lines
255264 int cnt;
256265
257266 tr = prog->aux->trampoline;
258− kind = bpf_attach_type_to_tramp(prog->expected_attach_type);
267+ kind = bpf_attach_type_to_tramp(prog);
259268 mutex_lock(&tr->mutex);
260269 if (tr->extension_prog) {
261270 /* cannot attach fentry/fexit if extension prog is attached.
@@ -305,7 +314,7 @@ int bpf_trampoline_unlink_prog(struct bpf_prog *prog) · 43 unmodified lines
305314 int err;
306315
307316 tr = prog->aux->trampoline;
308− kind = bpf_attach_type_to_tramp(prog->expected_attach_type);
317+ kind = bpf_attach_type_to_tramp(prog);
309318 mutex_lock(&tr->mutex);
310319 if (kind == BPF_TRAMP_REPLACE) {
311320 WARN_ON_ONCE(!tr->extension_prog);
kernel/bpf/verifier.c+15−4
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include <linux/perf_event.h>
2121 #include <linux/ctype.h>
2222 #include <linux/error-injection.h>
23+#include <linux/bpf_lsm.h>
2324
2425 #include "disasm.h"
2526
@@ -6492,8 +6493,9 @@ static int check_return_code(struct bpf_verifier_env *env) · 6466 unmodified lines
64926493 struct tnum range = tnum_range(0, 1);
64936494 int err;
64946495
6495− /* The struct_ops func-ptr's return type could be "void" */
6496− if (env->prog->type == BPF_PROG_TYPE_STRUCT_OPS &&
6496+ /* LSM and struct_ops func-ptr's return type could be "void" */
6497+ if ((env->prog->type == BPF_PROG_TYPE_STRUCT_OPS ||
6498+ env->prog->type == BPF_PROG_TYPE_LSM) &&
64976499 !prog->aux->attach_func_proto->type)
64986500 return 0;
64996501
@@ -9923,7 +9925,9 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) · 3423 unmodified lines
99239925 if (prog->type == BPF_PROG_TYPE_STRUCT_OPS)
99249926 return check_struct_ops_btf_id(env);
99259927
9926− if (prog->type != BPF_PROG_TYPE_TRACING && !prog_extension)
9928+ if (prog->type != BPF_PROG_TYPE_TRACING &&
9929+ prog->type != BPF_PROG_TYPE_LSM &&
9930+ !prog_extension)
99279931 return 0;
99289932
99299933 if (!btf_id) {
@@ -10054,8 +10058,16 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) · 124 unmodified lines
1005410058 return -EINVAL;
1005510059 /* fallthrough */
1005610060 case BPF_MODIFY_RETURN:
10061+ case BPF_LSM_MAC:
1005710062 case BPF_TRACE_FENTRY:
1005810063 case BPF_TRACE_FEXIT:
10064+ prog->aux->attach_func_name = tname;
10065+ if (prog->type == BPF_PROG_TYPE_LSM) {
10066+ ret = bpf_lsm_verify_prog(&env->log, prog);
10067+ if (ret < 0)
10068+ return ret;
10069+ }
10070+
1005910071 if (!btf_type_is_func(t)) {
1006010072 verbose(env, "attach_btf_id %u is not a function\n",
1006110073 btf_id);
@@ -10070,7 +10082,6 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) · 8 unmodified lines
1007010082 tr = bpf_trampoline_lookup(key);
1007110083 if (!tr)
1007210084 return -ENOMEM;
10073− prog->aux->attach_func_name = tname;
1007410085 /* t is either vmlinux type or another program's type */
1007510086 prog->aux->attach_func_proto = t;
1007610087 mutex_lock(&tr->mutex);