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(¶ms.algo, algo, sizeof(algo));
7291541ab1SVadim Fedorenko __builtin_memcpy(¶ms.key, key, sizeof(key));
7391541ab1SVadim Fedorenko cctx = bpf_crypto_ctx_create(¶ms, 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