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
test_sockmap_delete(void)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
test_sockmap_update(void * sk)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
test_sockmap_lookup_and_update(void)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
test_sockmap_mutate(void * sk)64 static __always_inline void test_sockmap_mutate(void *sk)
65 {
66 test_sockmap_delete();
67 test_sockmap_update(sk);
68 }
69
test_sockmap_lookup_and_mutate(void)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
test_sched_act(struct __sk_buff * skb)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
test_sched_cls(struct __sk_buff * skb)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
test_flow_dissector_delete(struct __sk_buff * skb __always_unused)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")
test_flow_dissector_update(struct __sk_buff * skb __always_unused)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
test_trace_iter(struct bpf_iter__sockmap * ctx)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")
test_raw_tp_delete(const void * ctx __always_unused)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")
test_raw_tp_update(const void * ctx __always_unused)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
test_sk_lookup(struct bpf_sk_lookup * ctx)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
test_sk_reuseport(struct sk_reuseport_md * ctx)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
test_socket_filter(struct __sk_buff * skb)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
test_sockops_delete(struct bpf_sock_ops * ctx __always_unused)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")
test_sockops_update(struct bpf_sock_ops * ctx)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
test_sockops_update_dedicated(struct bpf_sock_ops * ctx)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
test_xdp(struct xdp_md * ctx __always_unused)183 int test_xdp(struct xdp_md *ctx __always_unused)
184 {
185 test_sockmap_lookup_and_mutate();
186 return XDP_PASS;
187 }
188