1 // SPDX-License-Identifier: GPL-2.0 2 #include <netinet/in.h> 3 #include <linux/bpf.h> 4 #include "bpf_helpers.h" 5 6 char _license[] SEC("license") = "GPL"; 7 __u32 _version SEC("version") = 1; 8 9 #define SOL_CUSTOM 0xdeadbeef 10 11 struct sockopt_sk { 12 __u8 val; 13 }; 14 15 struct bpf_map_def SEC("maps") socket_storage_map = { 16 .type = BPF_MAP_TYPE_SK_STORAGE, 17 .key_size = sizeof(int), 18 .value_size = sizeof(struct sockopt_sk), 19 .map_flags = BPF_F_NO_PREALLOC, 20 }; 21 BPF_ANNOTATE_KV_PAIR(socket_storage_map, int, struct sockopt_sk); 22 23 SEC("cgroup/getsockopt") 24 int _getsockopt(struct bpf_sockopt *ctx) 25 { 26 __u8 *optval_end = ctx->optval_end; 27 __u8 *optval = ctx->optval; 28 struct sockopt_sk *storage; 29 30 if (ctx->level == SOL_IP && ctx->optname == IP_TOS) 31 /* Not interested in SOL_IP:IP_TOS; 32 * let next BPF program in the cgroup chain or kernel 33 * handle it. 34 */ 35 return 1; 36 37 if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) { 38 /* Not interested in SOL_SOCKET:SO_SNDBUF; 39 * let next BPF program in the cgroup chain or kernel 40 * handle it. 41 */ 42 return 1; 43 } 44 45 if (ctx->level != SOL_CUSTOM) 46 return 0; /* EPERM, deny everything except custom level */ 47 48 if (optval + 1 > optval_end) 49 return 0; /* EPERM, bounds check */ 50 51 storage = bpf_sk_storage_get(&socket_storage_map, ctx->sk, 0, 52 BPF_SK_STORAGE_GET_F_CREATE); 53 if (!storage) 54 return 0; /* EPERM, couldn't get sk storage */ 55 56 if (!ctx->retval) 57 return 0; /* EPERM, kernel should not have handled 58 * SOL_CUSTOM, something is wrong! 59 */ 60 ctx->retval = 0; /* Reset system call return value to zero */ 61 62 optval[0] = storage->val; 63 ctx->optlen = 1; 64 65 return 1; 66 } 67 68 SEC("cgroup/setsockopt") 69 int _setsockopt(struct bpf_sockopt *ctx) 70 { 71 __u8 *optval_end = ctx->optval_end; 72 __u8 *optval = ctx->optval; 73 struct sockopt_sk *storage; 74 75 if (ctx->level == SOL_IP && ctx->optname == IP_TOS) 76 /* Not interested in SOL_IP:IP_TOS; 77 * let next BPF program in the cgroup chain or kernel 78 * handle it. 79 */ 80 return 1; 81 82 if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) { 83 /* Overwrite SO_SNDBUF value */ 84 85 if (optval + sizeof(__u32) > optval_end) 86 return 0; /* EPERM, bounds check */ 87 88 *(__u32 *)optval = 0x55AA; 89 ctx->optlen = 4; 90 91 return 1; 92 } 93 94 if (ctx->level != SOL_CUSTOM) 95 return 0; /* EPERM, deny everything except custom level */ 96 97 if (optval + 1 > optval_end) 98 return 0; /* EPERM, bounds check */ 99 100 storage = bpf_sk_storage_get(&socket_storage_map, ctx->sk, 0, 101 BPF_SK_STORAGE_GET_F_CREATE); 102 if (!storage) 103 return 0; /* EPERM, couldn't get sk storage */ 104 105 storage->val = optval[0]; 106 ctx->optlen = -1; /* BPF has consumed this option, don't call kernel 107 * setsockopt handler. 108 */ 109 110 return 1; 111 } 112