1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include "cgroup_helpers.h" 4 5 #define SOL_CUSTOM 0xdeadbeef 6 7 static int getsetsockopt(void) 8 { 9 int fd, err; 10 union { 11 char u8[4]; 12 __u32 u32; 13 char cc[16]; /* TCP_CA_NAME_MAX */ 14 } buf = {}; 15 socklen_t optlen; 16 char *big_buf = NULL; 17 18 fd = socket(AF_INET, SOCK_STREAM, 0); 19 if (fd < 0) { 20 log_err("Failed to create socket"); 21 return -1; 22 } 23 24 /* IP_TOS - BPF bypass */ 25 26 optlen = getpagesize() * 2; 27 big_buf = calloc(1, optlen); 28 if (!big_buf) { 29 log_err("Couldn't allocate two pages"); 30 goto err; 31 } 32 33 *(int *)big_buf = 0x08; 34 err = setsockopt(fd, SOL_IP, IP_TOS, big_buf, optlen); 35 if (err) { 36 log_err("Failed to call setsockopt(IP_TOS)"); 37 goto err; 38 } 39 40 memset(big_buf, 0, optlen); 41 optlen = 1; 42 err = getsockopt(fd, SOL_IP, IP_TOS, big_buf, &optlen); 43 if (err) { 44 log_err("Failed to call getsockopt(IP_TOS)"); 45 goto err; 46 } 47 48 if (*(int *)big_buf != 0x08) { 49 log_err("Unexpected getsockopt(IP_TOS) optval 0x%x != 0x08", 50 *(int *)big_buf); 51 goto err; 52 } 53 54 /* IP_TTL - EPERM */ 55 56 buf.u8[0] = 1; 57 err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1); 58 if (!err || errno != EPERM) { 59 log_err("Unexpected success from setsockopt(IP_TTL)"); 60 goto err; 61 } 62 63 /* SOL_CUSTOM - handled by BPF */ 64 65 buf.u8[0] = 0x01; 66 err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1); 67 if (err) { 68 log_err("Failed to call setsockopt"); 69 goto err; 70 } 71 72 buf.u32 = 0x00; 73 optlen = 4; 74 err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen); 75 if (err) { 76 log_err("Failed to call getsockopt"); 77 goto err; 78 } 79 80 if (optlen != 1) { 81 log_err("Unexpected optlen %d != 1", optlen); 82 goto err; 83 } 84 if (buf.u8[0] != 0x01) { 85 log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]); 86 goto err; 87 } 88 89 /* IP_FREEBIND - BPF can't access optval past PAGE_SIZE */ 90 91 optlen = getpagesize() * 2; 92 memset(big_buf, 0, optlen); 93 94 err = setsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, optlen); 95 if (err != 0) { 96 log_err("Failed to call setsockopt, ret=%d", err); 97 goto err; 98 } 99 100 err = getsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, &optlen); 101 if (err != 0) { 102 log_err("Failed to call getsockopt, ret=%d", err); 103 goto err; 104 } 105 106 if (optlen != 1 || *(__u8 *)big_buf != 0x55) { 107 log_err("Unexpected IP_FREEBIND getsockopt, optlen=%d, optval=0x%x", 108 optlen, *(__u8 *)big_buf); 109 } 110 111 /* SO_SNDBUF is overwritten */ 112 113 buf.u32 = 0x01010101; 114 err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4); 115 if (err) { 116 log_err("Failed to call setsockopt(SO_SNDBUF)"); 117 goto err; 118 } 119 120 buf.u32 = 0x00; 121 optlen = 4; 122 err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen); 123 if (err) { 124 log_err("Failed to call getsockopt(SO_SNDBUF)"); 125 goto err; 126 } 127 128 if (buf.u32 != 0x55AA*2) { 129 log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2", 130 buf.u32); 131 goto err; 132 } 133 134 /* TCP_CONGESTION can extend the string */ 135 136 strcpy(buf.cc, "nv"); 137 err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv")); 138 if (err) { 139 log_err("Failed to call setsockopt(TCP_CONGESTION)"); 140 goto err; 141 } 142 143 144 optlen = sizeof(buf.cc); 145 err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen); 146 if (err) { 147 log_err("Failed to call getsockopt(TCP_CONGESTION)"); 148 goto err; 149 } 150 151 if (strcmp(buf.cc, "cubic") != 0) { 152 log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s", 153 buf.cc, "cubic"); 154 goto err; 155 } 156 157 free(big_buf); 158 close(fd); 159 return 0; 160 err: 161 free(big_buf); 162 close(fd); 163 return -1; 164 } 165 166 static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title) 167 { 168 enum bpf_attach_type attach_type; 169 enum bpf_prog_type prog_type; 170 struct bpf_program *prog; 171 int err; 172 173 err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); 174 if (err) { 175 log_err("Failed to deduct types for %s BPF program", title); 176 return -1; 177 } 178 179 prog = bpf_object__find_program_by_title(obj, title); 180 if (!prog) { 181 log_err("Failed to find %s BPF program", title); 182 return -1; 183 } 184 185 err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, 186 attach_type, 0); 187 if (err) { 188 log_err("Failed to attach %s BPF program", title); 189 return -1; 190 } 191 192 return 0; 193 } 194 195 static void run_test(int cgroup_fd) 196 { 197 struct bpf_prog_load_attr attr = { 198 .file = "./sockopt_sk.o", 199 }; 200 struct bpf_object *obj; 201 int ignored; 202 int err; 203 204 err = bpf_prog_load_xattr(&attr, &obj, &ignored); 205 if (CHECK_FAIL(err)) 206 return; 207 208 err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt"); 209 if (CHECK_FAIL(err)) 210 goto close_bpf_object; 211 212 err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt"); 213 if (CHECK_FAIL(err)) 214 goto close_bpf_object; 215 216 CHECK_FAIL(getsetsockopt()); 217 218 close_bpf_object: 219 bpf_object__close(obj); 220 } 221 222 void test_sockopt_sk(void) 223 { 224 int cgroup_fd; 225 226 cgroup_fd = test__join_cgroup("/sockopt_sk"); 227 if (CHECK_FAIL(cgroup_fd < 0)) 228 return; 229 230 run_test(cgroup_fd); 231 close(cgroup_fd); 232 } 233