xref: /linux/tools/testing/selftests/bpf/progs/verifier_sockmap_mutate.c (revision c94cd9508b1335b949fd13ebd269313c65492df0)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/bpf.h>
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_tracing.h>
6 
7 #include "bpf_misc.h"
8 
9 #define __always_unused __attribute__((unused))
10 
11 char _license[] SEC("license") = "GPL";
12 
13 struct sock {
14 } __attribute__((preserve_access_index));
15 
16 struct bpf_iter__sockmap {
17 	union {
18 		struct sock *sk;
19 	};
20 } __attribute__((preserve_access_index));
21 
22 struct {
23 	__uint(type, BPF_MAP_TYPE_SOCKHASH);
24 	__uint(max_entries, 1);
25 	__type(key, int);
26 	__type(value, int);
27 } sockhash SEC(".maps");
28 
29 struct {
30 	__uint(type, BPF_MAP_TYPE_SOCKMAP);
31 	__uint(max_entries, 1);
32 	__type(key, int);
33 	__type(value, int);
34 } sockmap SEC(".maps");
35 
36 enum { CG_OK = 1 };
37 
38 int zero = 0;
39 
40 static __always_inline void test_sockmap_delete(void)
41 {
42 	bpf_map_delete_elem(&sockmap, &zero);
43 	bpf_map_delete_elem(&sockhash, &zero);
44 }
45 
46 static __always_inline void test_sockmap_update(void *sk)
47 {
48 	if (sk) {
49 		bpf_map_update_elem(&sockmap, &zero, sk, BPF_ANY);
50 		bpf_map_update_elem(&sockhash, &zero, sk, BPF_ANY);
51 	}
52 }
53 
54 static __always_inline void test_sockmap_lookup_and_update(void)
55 {
56 	struct bpf_sock *sk = bpf_map_lookup_elem(&sockmap, &zero);
57 
58 	if (sk) {
59 		test_sockmap_update(sk);
60 		bpf_sk_release(sk);
61 	}
62 }
63 
64 static __always_inline void test_sockmap_mutate(void *sk)
65 {
66 	test_sockmap_delete();
67 	test_sockmap_update(sk);
68 }
69 
70 static __always_inline void test_sockmap_lookup_and_mutate(void)
71 {
72 	test_sockmap_delete();
73 	test_sockmap_lookup_and_update();
74 }
75 
76 SEC("action")
77 __success
78 int test_sched_act(struct __sk_buff *skb)
79 {
80 	test_sockmap_mutate(skb->sk);
81 	return 0;
82 }
83 
84 SEC("classifier")
85 __success
86 int test_sched_cls(struct __sk_buff *skb)
87 {
88 	test_sockmap_mutate(skb->sk);
89 	return 0;
90 }
91 
92 SEC("flow_dissector")
93 __success
94 int test_flow_dissector_delete(struct __sk_buff *skb __always_unused)
95 {
96 	test_sockmap_delete();
97 	return 0;
98 }
99 
100 SEC("flow_dissector")
101 __failure __msg("program of this type cannot use helper bpf_sk_release")
102 int test_flow_dissector_update(struct __sk_buff *skb __always_unused)
103 {
104 	test_sockmap_lookup_and_update(); /* no access to skb->sk */
105 	return 0;
106 }
107 
108 SEC("iter/sockmap")
109 __success
110 int test_trace_iter(struct bpf_iter__sockmap *ctx)
111 {
112 	test_sockmap_mutate(ctx->sk);
113 	return 0;
114 }
115 
116 SEC("raw_tp/kfree")
117 __failure __msg("cannot update sockmap in this context")
118 int test_raw_tp_delete(const void *ctx __always_unused)
119 {
120 	test_sockmap_delete();
121 	return 0;
122 }
123 
124 SEC("raw_tp/kfree")
125 __failure __msg("cannot update sockmap in this context")
126 int test_raw_tp_update(const void *ctx __always_unused)
127 {
128 	test_sockmap_lookup_and_update();
129 	return 0;
130 }
131 
132 SEC("sk_lookup")
133 __success
134 int test_sk_lookup(struct bpf_sk_lookup *ctx)
135 {
136 	test_sockmap_mutate(ctx->sk);
137 	return 0;
138 }
139 
140 SEC("sk_reuseport")
141 __success
142 int test_sk_reuseport(struct sk_reuseport_md *ctx)
143 {
144 	test_sockmap_mutate(ctx->sk);
145 	return 0;
146 }
147 
148 SEC("socket")
149 __success
150 int test_socket_filter(struct __sk_buff *skb)
151 {
152 	test_sockmap_mutate(skb->sk);
153 	return 0;
154 }
155 
156 SEC("sockops")
157 __success
158 int test_sockops_delete(struct bpf_sock_ops *ctx __always_unused)
159 {
160 	test_sockmap_delete();
161 	return CG_OK;
162 }
163 
164 SEC("sockops")
165 __failure __msg("cannot update sockmap in this context")
166 int test_sockops_update(struct bpf_sock_ops *ctx)
167 {
168 	test_sockmap_update(ctx->sk);
169 	return CG_OK;
170 }
171 
172 SEC("sockops")
173 __success
174 int test_sockops_update_dedicated(struct bpf_sock_ops *ctx)
175 {
176 	bpf_sock_map_update(ctx, &sockmap, &zero, BPF_ANY);
177 	bpf_sock_hash_update(ctx, &sockhash, &zero, BPF_ANY);
178 	return CG_OK;
179 }
180 
181 SEC("xdp")
182 __success
183 int test_xdp(struct xdp_md *ctx __always_unused)
184 {
185 	test_sockmap_lookup_and_mutate();
186 	return XDP_PASS;
187 }
188