1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/bpf.h> |
3 | #include <bpf/bpf_helpers.h> |
4 | |
5 | char _license[] SEC("license" ) = "GPL" ; |
6 | |
7 | #define SOL_CUSTOM 0xdeadbeef |
8 | #define CUSTOM_INHERIT1 0 |
9 | #define CUSTOM_INHERIT2 1 |
10 | #define CUSTOM_LISTENER 2 |
11 | |
12 | __s32 page_size = 0; |
13 | |
14 | struct sockopt_inherit { |
15 | __u8 val; |
16 | }; |
17 | |
18 | struct { |
19 | __uint(type, BPF_MAP_TYPE_SK_STORAGE); |
20 | __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE); |
21 | __type(key, int); |
22 | __type(value, struct sockopt_inherit); |
23 | } cloned1_map SEC(".maps" ); |
24 | |
25 | struct { |
26 | __uint(type, BPF_MAP_TYPE_SK_STORAGE); |
27 | __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE); |
28 | __type(key, int); |
29 | __type(value, struct sockopt_inherit); |
30 | } cloned2_map SEC(".maps" ); |
31 | |
32 | struct { |
33 | __uint(type, BPF_MAP_TYPE_SK_STORAGE); |
34 | __uint(map_flags, BPF_F_NO_PREALLOC); |
35 | __type(key, int); |
36 | __type(value, struct sockopt_inherit); |
37 | } listener_only_map SEC(".maps" ); |
38 | |
39 | static __inline struct sockopt_inherit *get_storage(struct bpf_sockopt *ctx) |
40 | { |
41 | if (ctx->optname == CUSTOM_INHERIT1) |
42 | return bpf_sk_storage_get(&cloned1_map, ctx->sk, 0, |
43 | BPF_SK_STORAGE_GET_F_CREATE); |
44 | else if (ctx->optname == CUSTOM_INHERIT2) |
45 | return bpf_sk_storage_get(&cloned2_map, ctx->sk, 0, |
46 | BPF_SK_STORAGE_GET_F_CREATE); |
47 | else |
48 | return bpf_sk_storage_get(&listener_only_map, ctx->sk, 0, |
49 | BPF_SK_STORAGE_GET_F_CREATE); |
50 | } |
51 | |
52 | SEC("cgroup/getsockopt" ) |
53 | int _getsockopt(struct bpf_sockopt *ctx) |
54 | { |
55 | __u8 *optval_end = ctx->optval_end; |
56 | struct sockopt_inherit *storage; |
57 | __u8 *optval = ctx->optval; |
58 | |
59 | if (ctx->level != SOL_CUSTOM) |
60 | goto out; /* only interested in SOL_CUSTOM */ |
61 | |
62 | if (optval + 1 > optval_end) |
63 | return 0; /* EPERM, bounds check */ |
64 | |
65 | storage = get_storage(ctx); |
66 | if (!storage) |
67 | return 0; /* EPERM, couldn't get sk storage */ |
68 | |
69 | ctx->retval = 0; /* Reset system call return value to zero */ |
70 | |
71 | optval[0] = storage->val; |
72 | ctx->optlen = 1; |
73 | |
74 | return 1; |
75 | |
76 | out: |
77 | /* optval larger than PAGE_SIZE use kernel's buffer. */ |
78 | if (ctx->optlen > page_size) |
79 | ctx->optlen = 0; |
80 | return 1; |
81 | } |
82 | |
83 | SEC("cgroup/setsockopt" ) |
84 | int _setsockopt(struct bpf_sockopt *ctx) |
85 | { |
86 | __u8 *optval_end = ctx->optval_end; |
87 | struct sockopt_inherit *storage; |
88 | __u8 *optval = ctx->optval; |
89 | |
90 | if (ctx->level != SOL_CUSTOM) |
91 | goto out; /* only interested in SOL_CUSTOM */ |
92 | |
93 | if (optval + 1 > optval_end) |
94 | return 0; /* EPERM, bounds check */ |
95 | |
96 | storage = get_storage(ctx); |
97 | if (!storage) |
98 | return 0; /* EPERM, couldn't get sk storage */ |
99 | |
100 | storage->val = optval[0]; |
101 | ctx->optlen = -1; |
102 | |
103 | return 1; |
104 | |
105 | out: |
106 | /* optval larger than PAGE_SIZE use kernel's buffer. */ |
107 | if (ctx->optlen > page_size) |
108 | ctx->optlen = 0; |
109 | return 1; |
110 | } |
111 | |