aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf')
-rw-r--r--kernel/bpf/Makefile1
-rw-r--r--kernel/bpf/core.c10
-rw-r--r--kernel/bpf/offload.c182
-rw-r--r--kernel/bpf/syscall.c17
-rw-r--r--kernel/bpf/verifier.c15
5 files changed, 217 insertions, 8 deletions
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 16e95c8e749e..e691da0b3bab 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_BPF_SYSCALL) += disasm.o
7ifeq ($(CONFIG_NET),y) 7ifeq ($(CONFIG_NET),y)
8obj-$(CONFIG_BPF_SYSCALL) += devmap.o 8obj-$(CONFIG_BPF_SYSCALL) += devmap.o
9obj-$(CONFIG_BPF_SYSCALL) += cpumap.o 9obj-$(CONFIG_BPF_SYSCALL) += cpumap.o
10obj-$(CONFIG_BPF_SYSCALL) += offload.o
10ifeq ($(CONFIG_STREAM_PARSER),y) 11ifeq ($(CONFIG_STREAM_PARSER),y)
11obj-$(CONFIG_BPF_SYSCALL) += sockmap.o 12obj-$(CONFIG_BPF_SYSCALL) += sockmap.o
12endif 13endif
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 7fe448799d76..8a6c37762330 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1380,7 +1380,13 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
1380 * valid program, which in this case would simply not 1380 * valid program, which in this case would simply not
1381 * be JITed, but falls back to the interpreter. 1381 * be JITed, but falls back to the interpreter.
1382 */ 1382 */
1383 fp = bpf_int_jit_compile(fp); 1383 if (!bpf_prog_is_dev_bound(fp->aux)) {
1384 fp = bpf_int_jit_compile(fp);
1385 } else {
1386 *err = bpf_prog_offload_compile(fp);
1387 if (*err)
1388 return fp;
1389 }
1384 bpf_prog_lock_ro(fp); 1390 bpf_prog_lock_ro(fp);
1385 1391
1386 /* The tail call compatibility check can only be done at 1392 /* The tail call compatibility check can only be done at
@@ -1549,6 +1555,8 @@ static void bpf_prog_free_deferred(struct work_struct *work)
1549 struct bpf_prog_aux *aux; 1555 struct bpf_prog_aux *aux;
1550 1556
1551 aux = container_of(work, struct bpf_prog_aux, work); 1557 aux = container_of(work, struct bpf_prog_aux, work);
1558 if (bpf_prog_is_dev_bound(aux))
1559 bpf_prog_offload_destroy(aux->prog);
1552 bpf_jit_free(aux->prog); 1560 bpf_jit_free(aux->prog);
1553} 1561}
1554 1562
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
new file mode 100644
index 000000000000..5553e0e2f8b1
--- /dev/null
+++ b/kernel/bpf/offload.c
@@ -0,0 +1,182 @@
1#include <linux/bpf.h>
2#include <linux/bpf_verifier.h>
3#include <linux/bug.h>
4#include <linux/list.h>
5#include <linux/netdevice.h>
6#include <linux/printk.h>
7#include <linux/rtnetlink.h>
8
9/* protected by RTNL */
10static LIST_HEAD(bpf_prog_offload_devs);
11
12int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
13{
14 struct net *net = current->nsproxy->net_ns;
15 struct bpf_dev_offload *offload;
16
17 if (!capable(CAP_SYS_ADMIN))
18 return -EPERM;
19
20 if (attr->prog_flags)
21 return -EINVAL;
22
23 offload = kzalloc(sizeof(*offload), GFP_USER);
24 if (!offload)
25 return -ENOMEM;
26
27 offload->prog = prog;
28 init_waitqueue_head(&offload->verifier_done);
29
30 rtnl_lock();
31 offload->netdev = __dev_get_by_index(net, attr->prog_target_ifindex);
32 if (!offload->netdev) {
33 rtnl_unlock();
34 kfree(offload);
35 return -EINVAL;
36 }
37
38 prog->aux->offload = offload;
39 list_add_tail(&offload->offloads, &bpf_prog_offload_devs);
40 rtnl_unlock();
41
42 return 0;
43}
44
45static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd,
46 struct netdev_bpf *data)
47{
48 struct net_device *netdev = prog->aux->offload->netdev;
49
50 ASSERT_RTNL();
51
52 if (!netdev)
53 return -ENODEV;
54 if (!netdev->netdev_ops->ndo_bpf)
55 return -EOPNOTSUPP;
56
57 data->command = cmd;
58
59 return netdev->netdev_ops->ndo_bpf(netdev, data);
60}
61
62int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)
63{
64 struct netdev_bpf data = {};
65 int err;
66
67 data.verifier.prog = env->prog;
68
69 rtnl_lock();
70 err = __bpf_offload_ndo(env->prog, BPF_OFFLOAD_VERIFIER_PREP, &data);
71 if (err)
72 goto exit_unlock;
73
74 env->dev_ops = data.verifier.ops;
75
76 env->prog->aux->offload->dev_state = true;
77 env->prog->aux->offload->verifier_running = true;
78exit_unlock:
79 rtnl_unlock();
80 return err;
81}
82
83static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
84{
85 struct bpf_dev_offload *offload = prog->aux->offload;
86 struct netdev_bpf data = {};
87
88 data.offload.prog = prog;
89
90 if (offload->verifier_running)
91 wait_event(offload->verifier_done, !offload->verifier_running);
92
93 if (offload->dev_state)
94 WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data));
95
96 offload->dev_state = false;
97 list_del_init(&offload->offloads);
98 offload->netdev = NULL;
99}
100
101void bpf_prog_offload_destroy(struct bpf_prog *prog)
102{
103 struct bpf_dev_offload *offload = prog->aux->offload;
104
105 offload->verifier_running = false;
106 wake_up(&offload->verifier_done);
107
108 rtnl_lock();
109 __bpf_prog_offload_destroy(prog);
110 rtnl_unlock();
111
112 kfree(offload);
113}
114
115static int bpf_prog_offload_translate(struct bpf_prog *prog)
116{
117 struct bpf_dev_offload *offload = prog->aux->offload;
118 struct netdev_bpf data = {};
119 int ret;
120
121 data.offload.prog = prog;
122
123 offload->verifier_running = false;
124 wake_up(&offload->verifier_done);
125
126 rtnl_lock();
127 ret = __bpf_offload_ndo(prog, BPF_OFFLOAD_TRANSLATE, &data);
128 rtnl_unlock();
129
130 return ret;
131}
132
133static unsigned int bpf_prog_warn_on_exec(const void *ctx,
134 const struct bpf_insn *insn)
135{
136 WARN(1, "attempt to execute device eBPF program on the host!");
137 return 0;
138}
139
140int bpf_prog_offload_compile(struct bpf_prog *prog)
141{
142 prog->bpf_func = bpf_prog_warn_on_exec;
143
144 return bpf_prog_offload_translate(prog);
145}
146
147const struct bpf_prog_ops bpf_offload_prog_ops = {
148};
149
150static int bpf_offload_notification(struct notifier_block *notifier,
151 ulong event, void *ptr)
152{
153 struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
154 struct bpf_dev_offload *offload, *tmp;
155
156 ASSERT_RTNL();
157
158 switch (event) {
159 case NETDEV_UNREGISTER:
160 list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs,
161 offloads) {
162 if (offload->netdev == netdev)
163 __bpf_prog_offload_destroy(offload->prog);
164 }
165 break;
166 default:
167 break;
168 }
169 return NOTIFY_OK;
170}
171
172static struct notifier_block bpf_offload_notifier = {
173 .notifier_call = bpf_offload_notification,
174};
175
176static int __init bpf_offload_init(void)
177{
178 register_netdevice_notifier(&bpf_offload_notifier);
179 return 0;
180}
181
182subsys_initcall(bpf_offload_init);
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 323be2473c4b..1574b9f0f24e 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -824,7 +824,10 @@ static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
824 if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type]) 824 if (type >= ARRAY_SIZE(bpf_prog_types) || !bpf_prog_types[type])
825 return -EINVAL; 825 return -EINVAL;
826 826
827 prog->aux->ops = bpf_prog_types[type]; 827 if (!bpf_prog_is_dev_bound(prog->aux))
828 prog->aux->ops = bpf_prog_types[type];
829 else
830 prog->aux->ops = &bpf_offload_prog_ops;
828 prog->type = type; 831 prog->type = type;
829 return 0; 832 return 0;
830} 833}
@@ -1054,7 +1057,7 @@ struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
1054} 1057}
1055EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero); 1058EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
1056 1059
1057static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type) 1060static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type)
1058{ 1061{
1059 struct fd f = fdget(ufd); 1062 struct fd f = fdget(ufd);
1060 struct bpf_prog *prog; 1063 struct bpf_prog *prog;
@@ -1062,7 +1065,7 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type)
1062 prog = ____bpf_prog_get(f); 1065 prog = ____bpf_prog_get(f);
1063 if (IS_ERR(prog)) 1066 if (IS_ERR(prog))
1064 return prog; 1067 return prog;
1065 if (type && prog->type != *type) { 1068 if (attach_type && (prog->type != *attach_type || prog->aux->offload)) {
1066 prog = ERR_PTR(-EINVAL); 1069 prog = ERR_PTR(-EINVAL);
1067 goto out; 1070 goto out;
1068 } 1071 }
@@ -1089,7 +1092,7 @@ struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
1089EXPORT_SYMBOL_GPL(bpf_prog_get_type); 1092EXPORT_SYMBOL_GPL(bpf_prog_get_type);
1090 1093
1091/* last field in 'union bpf_attr' used by this command */ 1094/* last field in 'union bpf_attr' used by this command */
1092#define BPF_PROG_LOAD_LAST_FIELD prog_name 1095#define BPF_PROG_LOAD_LAST_FIELD prog_target_ifindex
1093 1096
1094static int bpf_prog_load(union bpf_attr *attr) 1097static int bpf_prog_load(union bpf_attr *attr)
1095{ 1098{
@@ -1152,6 +1155,12 @@ static int bpf_prog_load(union bpf_attr *attr)
1152 atomic_set(&prog->aux->refcnt, 1); 1155 atomic_set(&prog->aux->refcnt, 1);
1153 prog->gpl_compatible = is_gpl ? 1 : 0; 1156 prog->gpl_compatible = is_gpl ? 1 : 0;
1154 1157
1158 if (attr->prog_target_ifindex) {
1159 err = bpf_prog_offload_init(prog, attr);
1160 if (err)
1161 goto free_prog;
1162 }
1163
1155 /* find program type: socket_filter vs tracing_filter */ 1164 /* find program type: socket_filter vs tracing_filter */
1156 err = find_prog_type(type, prog); 1165 err = find_prog_type(type, prog);
1157 if (err < 0) 1166 if (err < 0)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 04357ad5a812..51aabb32ad67 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3736,10 +3736,13 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
3736static int ext_analyzer_insn_hook(struct bpf_verifier_env *env, 3736static int ext_analyzer_insn_hook(struct bpf_verifier_env *env,
3737 int insn_idx, int prev_insn_idx) 3737 int insn_idx, int prev_insn_idx)
3738{ 3738{
3739 if (!env->analyzer_ops || !env->analyzer_ops->insn_hook) 3739 if (env->analyzer_ops && env->analyzer_ops->insn_hook)
3740 return 0; 3740 return env->analyzer_ops->insn_hook(env, insn_idx,
3741 prev_insn_idx);
3742 if (env->dev_ops && env->dev_ops->insn_hook)
3743 return env->dev_ops->insn_hook(env, insn_idx, prev_insn_idx);
3741 3744
3742 return env->analyzer_ops->insn_hook(env, insn_idx, prev_insn_idx); 3745 return 0;
3743} 3746}
3744 3747
3745static int do_check(struct bpf_verifier_env *env) 3748static int do_check(struct bpf_verifier_env *env)
@@ -4516,6 +4519,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
4516 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) 4519 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
4517 env->strict_alignment = true; 4520 env->strict_alignment = true;
4518 4521
4522 if (env->prog->aux->offload) {
4523 ret = bpf_prog_offload_verifier_prep(env);
4524 if (ret)
4525 goto err_unlock;
4526 }
4527
4519 ret = replace_map_fd_with_map_ptr(env); 4528 ret = replace_map_fd_with_map_ptr(env);
4520 if (ret < 0) 4529 if (ret < 0)
4521 goto skip_full_check; 4530 goto skip_full_check;