xref: /linux/tools/testing/selftests/bpf/progs/crypto_sanity.c (revision 594ce0b8a998aa4d05827cd7c0d0dcec9a1e3ae2)
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] = {};
18 int status;
19 
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")
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 = 0;
63 
64 	status = 0;
65 
66 	if (key_len > 256) {
67 		status = -EINVAL;
68 		return 0;
69 	}
70 
71 	__builtin_memcpy(&params.algo, algo, sizeof(algo));
72 	__builtin_memcpy(&params.key, key, sizeof(key));
73 	cctx = bpf_crypto_ctx_create(&params, sizeof(params), &err);
74 
75 	if (!cctx) {
76 		status = err;
77 		return 0;
78 	}
79 
80 	err = crypto_ctx_insert(cctx);
81 	if (err && err != -EEXIST)
82 		status = err;
83 
84 	return 0;
85 }
86 
87 SEC("tc")
88 int decrypt_sanity(struct __sk_buff *skb)
89 {
90 	struct __crypto_ctx_value *v;
91 	struct bpf_crypto_ctx *ctx;
92 	struct bpf_dynptr psrc, pdst, iv;
93 	int err;
94 
95 	err = skb_dynptr_validate(skb, &psrc);
96 	if (err < 0) {
97 		status = err;
98 		return TC_ACT_SHOT;
99 	}
100 
101 	v = crypto_ctx_value_lookup();
102 	if (!v) {
103 		status = -ENOENT;
104 		return TC_ACT_SHOT;
105 	}
106 
107 	ctx = v->ctx;
108 	if (!ctx) {
109 		status = -ENOENT;
110 		return TC_ACT_SHOT;
111 	}
112 
113 	/* dst is a global variable to make testing part easier to check. In real
114 	 * production code, a percpu map should be used to store the result.
115 	 */
116 	bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst);
117 	/* iv dynptr has to be initialized with 0 size, but proper memory region
118 	 * has to be provided anyway
119 	 */
120 	bpf_dynptr_from_mem(dst, 0, 0, &iv);
121 
122 	status = bpf_crypto_decrypt(ctx, &psrc, &pdst, &iv);
123 
124 	return TC_ACT_SHOT;
125 }
126 
127 SEC("tc")
128 int encrypt_sanity(struct __sk_buff *skb)
129 {
130 	struct __crypto_ctx_value *v;
131 	struct bpf_crypto_ctx *ctx;
132 	struct bpf_dynptr psrc, pdst, iv;
133 	int err;
134 
135 	status = 0;
136 
137 	err = skb_dynptr_validate(skb, &psrc);
138 	if (err < 0) {
139 		status = err;
140 		return TC_ACT_SHOT;
141 	}
142 
143 	v = crypto_ctx_value_lookup();
144 	if (!v) {
145 		status = -ENOENT;
146 		return TC_ACT_SHOT;
147 	}
148 
149 	ctx = v->ctx;
150 	if (!ctx) {
151 		status = -ENOENT;
152 		return TC_ACT_SHOT;
153 	}
154 
155 	/* dst is a global variable to make testing part easier to check. In real
156 	 * production code, a percpu map should be used to store the result.
157 	 */
158 	bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst);
159 	/* iv dynptr has to be initialized with 0 size, but proper memory region
160 	 * has to be provided anyway
161 	 */
162 	bpf_dynptr_from_mem(dst, 0, 0, &iv);
163 
164 	status = bpf_crypto_encrypt(ctx, &psrc, &pdst, &iv);
165 
166 	return TC_ACT_SHOT;
167 }
168 
169 char __license[] SEC("license") = "GPL";
170