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