1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3
4 #include "vmlinux.h"
5 #include "bpf_tracing_net.h"
6 #include <bpf/bpf_helpers.h>
7 #include <bpf/bpf_endian.h>
8 #include <bpf/bpf_tracing.h>
9 #include "bpf_misc.h"
10 #include "bpf_kfuncs.h"
11 #include "crypto_common.h"
12
13 unsigned char key[256] = {};
14 u16 udp_test_port = 7777;
15 u32 authsize, key_len;
16 char algo[128] = {};
17 char dst[16] = {}, dst_bad[8] = {};
18 int status;
19
skb_dynptr_validate(struct __sk_buff * skb,struct bpf_dynptr * psrc)20 static int skb_dynptr_validate(struct __sk_buff *skb, struct bpf_dynptr *psrc)
21 {
22 struct ipv6hdr ip6h;
23 struct udphdr udph;
24 u32 offset;
25
26 if (skb->protocol != __bpf_constant_htons(ETH_P_IPV6))
27 return -1;
28
29 if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip6h, sizeof(ip6h)))
30 return -1;
31
32 if (ip6h.nexthdr != IPPROTO_UDP)
33 return -1;
34
35 if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(ip6h), &udph, sizeof(udph)))
36 return -1;
37
38 if (udph.dest != __bpf_htons(udp_test_port))
39 return -1;
40
41 offset = ETH_HLEN + sizeof(ip6h) + sizeof(udph);
42 if (skb->len < offset + 16)
43 return -1;
44
45 /* let's make sure that 16 bytes of payload are in the linear part of skb */
46 bpf_skb_pull_data(skb, offset + 16);
47 bpf_dynptr_from_skb(skb, 0, psrc);
48 bpf_dynptr_adjust(psrc, offset, offset + 16);
49
50 return 0;
51 }
52
53 SEC("syscall")
skb_crypto_setup(void * ctx)54 int skb_crypto_setup(void *ctx)
55 {
56 struct bpf_crypto_params params = {
57 .type = "skcipher",
58 .key_len = key_len,
59 .authsize = authsize,
60 };
61 struct bpf_crypto_ctx *cctx;
62 int err;
63
64 status = 0;
65 if (key_len > 256) {
66 status = -EINVAL;
67 return 0;
68 }
69
70 __builtin_memcpy(¶ms.algo, algo, sizeof(algo));
71 __builtin_memcpy(¶ms.key, key, sizeof(key));
72
73 cctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &err);
74 if (!cctx) {
75 status = err;
76 return 0;
77 }
78
79 err = crypto_ctx_insert(cctx);
80 if (err && err != -EEXIST)
81 status = err;
82 return 0;
83 }
84
85 SEC("tc")
decrypt_sanity(struct __sk_buff * skb)86 int decrypt_sanity(struct __sk_buff *skb)
87 {
88 struct __crypto_ctx_value *v;
89 struct bpf_crypto_ctx *ctx;
90 struct bpf_dynptr psrc, pdst;
91 int err;
92
93 status = 0;
94 err = skb_dynptr_validate(skb, &psrc);
95 if (err < 0) {
96 status = err;
97 return TC_ACT_SHOT;
98 }
99
100 v = crypto_ctx_value_lookup();
101 if (!v) {
102 status = -ENOENT;
103 return TC_ACT_SHOT;
104 }
105
106 ctx = v->ctx;
107 if (!ctx) {
108 status = -ENOENT;
109 return TC_ACT_SHOT;
110 }
111
112 /* Check also bad case where the dst buffer is smaller than the
113 * skb's linear section.
114 */
115 bpf_dynptr_from_mem(dst_bad, sizeof(dst_bad), 0, &pdst);
116 status = bpf_crypto_decrypt(ctx, &psrc, &pdst, NULL);
117 if (!status)
118 status = -EIO;
119 if (status != -EINVAL)
120 goto err;
121
122 /* dst is a global variable to make testing part easier to check.
123 * In real production code, a percpu map should be used to store
124 * the result.
125 */
126 bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst);
127 status = bpf_crypto_decrypt(ctx, &psrc, &pdst, NULL);
128 err:
129 return TC_ACT_SHOT;
130 }
131
132 SEC("tc")
encrypt_sanity(struct __sk_buff * skb)133 int encrypt_sanity(struct __sk_buff *skb)
134 {
135 struct __crypto_ctx_value *v;
136 struct bpf_crypto_ctx *ctx;
137 struct bpf_dynptr psrc, pdst;
138 int err;
139
140 status = 0;
141 err = skb_dynptr_validate(skb, &psrc);
142 if (err < 0) {
143 status = err;
144 return TC_ACT_SHOT;
145 }
146
147 v = crypto_ctx_value_lookup();
148 if (!v) {
149 status = -ENOENT;
150 return TC_ACT_SHOT;
151 }
152
153 ctx = v->ctx;
154 if (!ctx) {
155 status = -ENOENT;
156 return TC_ACT_SHOT;
157 }
158
159 /* Check also bad case where the dst buffer is smaller than the
160 * skb's linear section.
161 */
162 bpf_dynptr_from_mem(dst_bad, sizeof(dst_bad), 0, &pdst);
163 status = bpf_crypto_encrypt(ctx, &psrc, &pdst, NULL);
164 if (!status)
165 status = -EIO;
166 if (status != -EINVAL)
167 goto err;
168
169 /* dst is a global variable to make testing part easier to check.
170 * In real production code, a percpu map should be used to store
171 * the result.
172 */
173 bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst);
174 status = bpf_crypto_encrypt(ctx, &psrc, &pdst, NULL);
175 err:
176 return TC_ACT_SHOT;
177 }
178
179 char __license[] SEC("license") = "GPL";
180