xref: /linux/tools/testing/selftests/bpf/progs/crypto_sanity.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
191541ab1SVadim Fedorenko // SPDX-License-Identifier: GPL-2.0
291541ab1SVadim Fedorenko /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
391541ab1SVadim Fedorenko 
491541ab1SVadim Fedorenko #include "vmlinux.h"
591541ab1SVadim Fedorenko #include "bpf_tracing_net.h"
691541ab1SVadim Fedorenko #include <bpf/bpf_helpers.h>
791541ab1SVadim Fedorenko #include <bpf/bpf_endian.h>
891541ab1SVadim Fedorenko #include <bpf/bpf_tracing.h>
991541ab1SVadim Fedorenko #include "bpf_misc.h"
1091541ab1SVadim Fedorenko #include "bpf_kfuncs.h"
1191541ab1SVadim Fedorenko #include "crypto_common.h"
1291541ab1SVadim Fedorenko 
1391541ab1SVadim Fedorenko unsigned char key[256] = {};
1491541ab1SVadim Fedorenko u16 udp_test_port = 7777;
1591541ab1SVadim Fedorenko u32 authsize, key_len;
1691541ab1SVadim Fedorenko char algo[128] = {};
1791541ab1SVadim Fedorenko char dst[16] = {};
1891541ab1SVadim Fedorenko int status;
1991541ab1SVadim Fedorenko 
skb_dynptr_validate(struct __sk_buff * skb,struct bpf_dynptr * psrc)2091541ab1SVadim Fedorenko static int skb_dynptr_validate(struct __sk_buff *skb, struct bpf_dynptr *psrc)
2191541ab1SVadim Fedorenko {
2291541ab1SVadim Fedorenko 	struct ipv6hdr ip6h;
2391541ab1SVadim Fedorenko 	struct udphdr udph;
2491541ab1SVadim Fedorenko 	u32 offset;
2591541ab1SVadim Fedorenko 
2691541ab1SVadim Fedorenko 	if (skb->protocol != __bpf_constant_htons(ETH_P_IPV6))
2791541ab1SVadim Fedorenko 		return -1;
2891541ab1SVadim Fedorenko 
2991541ab1SVadim Fedorenko 	if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip6h, sizeof(ip6h)))
3091541ab1SVadim Fedorenko 		return -1;
3191541ab1SVadim Fedorenko 
3291541ab1SVadim Fedorenko 	if (ip6h.nexthdr != IPPROTO_UDP)
3391541ab1SVadim Fedorenko 		return -1;
3491541ab1SVadim Fedorenko 
3591541ab1SVadim Fedorenko 	if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(ip6h), &udph, sizeof(udph)))
3691541ab1SVadim Fedorenko 		return -1;
3791541ab1SVadim Fedorenko 
3891541ab1SVadim Fedorenko 	if (udph.dest != __bpf_htons(udp_test_port))
3991541ab1SVadim Fedorenko 		return -1;
4091541ab1SVadim Fedorenko 
4191541ab1SVadim Fedorenko 	offset = ETH_HLEN + sizeof(ip6h) + sizeof(udph);
4291541ab1SVadim Fedorenko 	if (skb->len < offset + 16)
4391541ab1SVadim Fedorenko 		return -1;
4491541ab1SVadim Fedorenko 
4591541ab1SVadim Fedorenko 	/* let's make sure that 16 bytes of payload are in the linear part of skb */
4691541ab1SVadim Fedorenko 	bpf_skb_pull_data(skb, offset + 16);
4791541ab1SVadim Fedorenko 	bpf_dynptr_from_skb(skb, 0, psrc);
4891541ab1SVadim Fedorenko 	bpf_dynptr_adjust(psrc, offset, offset + 16);
4991541ab1SVadim Fedorenko 
5091541ab1SVadim Fedorenko 	return 0;
5191541ab1SVadim Fedorenko }
5291541ab1SVadim Fedorenko 
5391541ab1SVadim Fedorenko SEC("syscall")
skb_crypto_setup(void * ctx)5491541ab1SVadim Fedorenko int skb_crypto_setup(void *ctx)
5591541ab1SVadim Fedorenko {
5691541ab1SVadim Fedorenko 	struct bpf_crypto_params params = {
5791541ab1SVadim Fedorenko 		.type = "skcipher",
5891541ab1SVadim Fedorenko 		.key_len = key_len,
5991541ab1SVadim Fedorenko 		.authsize = authsize,
6091541ab1SVadim Fedorenko 	};
6191541ab1SVadim Fedorenko 	struct bpf_crypto_ctx *cctx;
6291541ab1SVadim Fedorenko 	int err = 0;
6391541ab1SVadim Fedorenko 
6491541ab1SVadim Fedorenko 	status = 0;
6591541ab1SVadim Fedorenko 
6691541ab1SVadim Fedorenko 	if (key_len > 256) {
6791541ab1SVadim Fedorenko 		status = -EINVAL;
6891541ab1SVadim Fedorenko 		return 0;
6991541ab1SVadim Fedorenko 	}
7091541ab1SVadim Fedorenko 
7191541ab1SVadim Fedorenko 	__builtin_memcpy(&params.algo, algo, sizeof(algo));
7291541ab1SVadim Fedorenko 	__builtin_memcpy(&params.key, key, sizeof(key));
7391541ab1SVadim Fedorenko 	cctx = bpf_crypto_ctx_create(&params, sizeof(params), &err);
7491541ab1SVadim Fedorenko 
7591541ab1SVadim Fedorenko 	if (!cctx) {
7691541ab1SVadim Fedorenko 		status = err;
7791541ab1SVadim Fedorenko 		return 0;
7891541ab1SVadim Fedorenko 	}
7991541ab1SVadim Fedorenko 
8091541ab1SVadim Fedorenko 	err = crypto_ctx_insert(cctx);
8191541ab1SVadim Fedorenko 	if (err && err != -EEXIST)
8291541ab1SVadim Fedorenko 		status = err;
8391541ab1SVadim Fedorenko 
8491541ab1SVadim Fedorenko 	return 0;
8591541ab1SVadim Fedorenko }
8691541ab1SVadim Fedorenko 
8791541ab1SVadim Fedorenko SEC("tc")
decrypt_sanity(struct __sk_buff * skb)8891541ab1SVadim Fedorenko int decrypt_sanity(struct __sk_buff *skb)
8991541ab1SVadim Fedorenko {
9091541ab1SVadim Fedorenko 	struct __crypto_ctx_value *v;
9191541ab1SVadim Fedorenko 	struct bpf_crypto_ctx *ctx;
92*9363dc8dSVadim Fedorenko 	struct bpf_dynptr psrc, pdst;
9391541ab1SVadim Fedorenko 	int err;
9491541ab1SVadim Fedorenko 
9591541ab1SVadim Fedorenko 	err = skb_dynptr_validate(skb, &psrc);
9691541ab1SVadim Fedorenko 	if (err < 0) {
9791541ab1SVadim Fedorenko 		status = err;
9891541ab1SVadim Fedorenko 		return TC_ACT_SHOT;
9991541ab1SVadim Fedorenko 	}
10091541ab1SVadim Fedorenko 
10191541ab1SVadim Fedorenko 	v = crypto_ctx_value_lookup();
10291541ab1SVadim Fedorenko 	if (!v) {
10391541ab1SVadim Fedorenko 		status = -ENOENT;
10491541ab1SVadim Fedorenko 		return TC_ACT_SHOT;
10591541ab1SVadim Fedorenko 	}
10691541ab1SVadim Fedorenko 
10791541ab1SVadim Fedorenko 	ctx = v->ctx;
10891541ab1SVadim Fedorenko 	if (!ctx) {
10991541ab1SVadim Fedorenko 		status = -ENOENT;
11091541ab1SVadim Fedorenko 		return TC_ACT_SHOT;
11191541ab1SVadim Fedorenko 	}
11291541ab1SVadim Fedorenko 
11391541ab1SVadim Fedorenko 	/* dst is a global variable to make testing part easier to check. In real
11491541ab1SVadim Fedorenko 	 * production code, a percpu map should be used to store the result.
11591541ab1SVadim Fedorenko 	 */
11691541ab1SVadim Fedorenko 	bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst);
11791541ab1SVadim Fedorenko 
118*9363dc8dSVadim Fedorenko 	status = bpf_crypto_decrypt(ctx, &psrc, &pdst, NULL);
11991541ab1SVadim Fedorenko 
12091541ab1SVadim Fedorenko 	return TC_ACT_SHOT;
12191541ab1SVadim Fedorenko }
12291541ab1SVadim Fedorenko 
12391541ab1SVadim Fedorenko SEC("tc")
encrypt_sanity(struct __sk_buff * skb)12491541ab1SVadim Fedorenko int encrypt_sanity(struct __sk_buff *skb)
12591541ab1SVadim Fedorenko {
12691541ab1SVadim Fedorenko 	struct __crypto_ctx_value *v;
12791541ab1SVadim Fedorenko 	struct bpf_crypto_ctx *ctx;
128*9363dc8dSVadim Fedorenko 	struct bpf_dynptr psrc, pdst;
12991541ab1SVadim Fedorenko 	int err;
13091541ab1SVadim Fedorenko 
13191541ab1SVadim Fedorenko 	status = 0;
13291541ab1SVadim Fedorenko 
13391541ab1SVadim Fedorenko 	err = skb_dynptr_validate(skb, &psrc);
13491541ab1SVadim Fedorenko 	if (err < 0) {
13591541ab1SVadim Fedorenko 		status = err;
13691541ab1SVadim Fedorenko 		return TC_ACT_SHOT;
13791541ab1SVadim Fedorenko 	}
13891541ab1SVadim Fedorenko 
13991541ab1SVadim Fedorenko 	v = crypto_ctx_value_lookup();
14091541ab1SVadim Fedorenko 	if (!v) {
14191541ab1SVadim Fedorenko 		status = -ENOENT;
14291541ab1SVadim Fedorenko 		return TC_ACT_SHOT;
14391541ab1SVadim Fedorenko 	}
14491541ab1SVadim Fedorenko 
14591541ab1SVadim Fedorenko 	ctx = v->ctx;
14691541ab1SVadim Fedorenko 	if (!ctx) {
14791541ab1SVadim Fedorenko 		status = -ENOENT;
14891541ab1SVadim Fedorenko 		return TC_ACT_SHOT;
14991541ab1SVadim Fedorenko 	}
15091541ab1SVadim Fedorenko 
15191541ab1SVadim Fedorenko 	/* dst is a global variable to make testing part easier to check. In real
15291541ab1SVadim Fedorenko 	 * production code, a percpu map should be used to store the result.
15391541ab1SVadim Fedorenko 	 */
15491541ab1SVadim Fedorenko 	bpf_dynptr_from_mem(dst, sizeof(dst), 0, &pdst);
15591541ab1SVadim Fedorenko 
156*9363dc8dSVadim Fedorenko 	status = bpf_crypto_encrypt(ctx, &psrc, &pdst, NULL);
15791541ab1SVadim Fedorenko 
15891541ab1SVadim Fedorenko 	return TC_ACT_SHOT;
15991541ab1SVadim Fedorenko }
16091541ab1SVadim Fedorenko 
16191541ab1SVadim Fedorenko char __license[] SEC("license") = "GPL";
162