260 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <test_progs.h>3#include "cgroup_helpers.h"4 5#include <linux/tcp.h>6#include <linux/netlink.h>7#include "sockopt_sk.skel.h"8 9#ifndef SOL_TCP10#define SOL_TCP IPPROTO_TCP11#endif12 13#define SOL_CUSTOM 0xdeadbeef14 15static int getsetsockopt(void)16{17 int fd, err;18 union {19 char u8[4];20 __u32 u32;21 char cc[16]; /* TCP_CA_NAME_MAX */22 struct tcp_zerocopy_receive zc;23 } buf = {};24 socklen_t optlen;25 char *big_buf = NULL;26 27 fd = socket(AF_INET, SOCK_STREAM, 0);28 if (fd < 0) {29 log_err("Failed to create socket");30 return -1;31 }32 33 /* IP_TOS - BPF bypass */34 35 optlen = getpagesize() * 2;36 big_buf = calloc(1, optlen);37 if (!big_buf) {38 log_err("Couldn't allocate two pages");39 goto err;40 }41 42 *(int *)big_buf = 0x08;43 err = setsockopt(fd, SOL_IP, IP_TOS, big_buf, optlen);44 if (err) {45 log_err("Failed to call setsockopt(IP_TOS)");46 goto err;47 }48 49 memset(big_buf, 0, optlen);50 optlen = 1;51 err = getsockopt(fd, SOL_IP, IP_TOS, big_buf, &optlen);52 if (err) {53 log_err("Failed to call getsockopt(IP_TOS)");54 goto err;55 }56 57 if (*big_buf != 0x08) {58 log_err("Unexpected getsockopt(IP_TOS) optval 0x%x != 0x08",59 (int)*big_buf);60 goto err;61 }62 63 /* IP_TTL - EPERM */64 65 buf.u8[0] = 1;66 err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1);67 if (!err || errno != EPERM) {68 log_err("Unexpected success from setsockopt(IP_TTL)");69 goto err;70 }71 72 /* SOL_CUSTOM - handled by BPF */73 74 buf.u8[0] = 0x01;75 err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1);76 if (err) {77 log_err("Failed to call setsockopt");78 goto err;79 }80 81 buf.u32 = 0x00;82 optlen = 4;83 err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen);84 if (err) {85 log_err("Failed to call getsockopt");86 goto err;87 }88 89 if (optlen != 1) {90 log_err("Unexpected optlen %d != 1", optlen);91 goto err;92 }93 if (buf.u8[0] != 0x01) {94 log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]);95 goto err;96 }97 98 /* IP_FREEBIND - BPF can't access optval past PAGE_SIZE */99 100 optlen = getpagesize() * 2;101 memset(big_buf, 0, optlen);102 103 err = setsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, optlen);104 if (err != 0) {105 log_err("Failed to call setsockopt, ret=%d", err);106 goto err;107 }108 109 err = getsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, &optlen);110 if (err != 0) {111 log_err("Failed to call getsockopt, ret=%d", err);112 goto err;113 }114 115 if (optlen != 1 || *(__u8 *)big_buf != 0x55) {116 log_err("Unexpected IP_FREEBIND getsockopt, optlen=%d, optval=0x%x",117 optlen, *(__u8 *)big_buf);118 }119 120 /* SO_SNDBUF is overwritten */121 122 buf.u32 = 0x01010101;123 err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4);124 if (err) {125 log_err("Failed to call setsockopt(SO_SNDBUF)");126 goto err;127 }128 129 buf.u32 = 0x00;130 optlen = 4;131 err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen);132 if (err) {133 log_err("Failed to call getsockopt(SO_SNDBUF)");134 goto err;135 }136 137 if (buf.u32 != 0x55AA*2) {138 log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2",139 buf.u32);140 goto err;141 }142 143 /* TCP_CONGESTION can extend the string */144 145 strcpy(buf.cc, "nv");146 err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv"));147 if (err) {148 log_err("Failed to call setsockopt(TCP_CONGESTION)");149 goto err;150 }151 152 153 optlen = sizeof(buf.cc);154 err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen);155 if (err) {156 log_err("Failed to call getsockopt(TCP_CONGESTION)");157 goto err;158 }159 160 if (strcmp(buf.cc, "cubic") != 0) {161 log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s",162 buf.cc, "cubic");163 goto err;164 }165 166 /* TCP_ZEROCOPY_RECEIVE triggers */167 memset(&buf, 0, sizeof(buf));168 optlen = sizeof(buf.zc);169 err = getsockopt(fd, SOL_TCP, TCP_ZEROCOPY_RECEIVE, &buf, &optlen);170 if (err) {171 log_err("Unexpected getsockopt(TCP_ZEROCOPY_RECEIVE) err=%d errno=%d",172 err, errno);173 goto err;174 }175 176 memset(&buf, 0, sizeof(buf));177 buf.zc.address = 12345; /* Not page aligned. Rejected by tcp_zerocopy_receive() */178 optlen = sizeof(buf.zc);179 errno = 0;180 err = getsockopt(fd, SOL_TCP, TCP_ZEROCOPY_RECEIVE, &buf, &optlen);181 if (errno != EINVAL) {182 log_err("Unexpected getsockopt(TCP_ZEROCOPY_RECEIVE) err=%d errno=%d",183 err, errno);184 goto err;185 }186 187 /* optval=NULL case is handled correctly */188 189 close(fd);190 fd = socket(AF_NETLINK, SOCK_RAW, 0);191 if (fd < 0) {192 log_err("Failed to create AF_NETLINK socket");193 return -1;194 }195 196 buf.u32 = 1;197 optlen = sizeof(__u32);198 err = setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &buf, optlen);199 if (err) {200 log_err("Unexpected getsockopt(NETLINK_ADD_MEMBERSHIP) err=%d errno=%d",201 err, errno);202 goto err;203 }204 205 optlen = 0;206 err = getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &optlen);207 if (err) {208 log_err("Unexpected getsockopt(NETLINK_LIST_MEMBERSHIPS) err=%d errno=%d",209 err, errno);210 goto err;211 }212 ASSERT_EQ(optlen, 8, "Unexpected NETLINK_LIST_MEMBERSHIPS value");213 214 free(big_buf);215 close(fd);216 return 0;217err:218 free(big_buf);219 close(fd);220 return -1;221}222 223static void run_test(int cgroup_fd)224{225 struct sockopt_sk *skel;226 227 skel = sockopt_sk__open_and_load();228 if (!ASSERT_OK_PTR(skel, "skel_load"))229 goto cleanup;230 231 skel->bss->page_size = getpagesize();232 233 skel->links._setsockopt =234 bpf_program__attach_cgroup(skel->progs._setsockopt, cgroup_fd);235 if (!ASSERT_OK_PTR(skel->links._setsockopt, "setsockopt_link"))236 goto cleanup;237 238 skel->links._getsockopt =239 bpf_program__attach_cgroup(skel->progs._getsockopt, cgroup_fd);240 if (!ASSERT_OK_PTR(skel->links._getsockopt, "getsockopt_link"))241 goto cleanup;242 243 ASSERT_OK(getsetsockopt(), "getsetsockopt");244 245cleanup:246 sockopt_sk__destroy(skel);247}248 249void test_sockopt_sk(void)250{251 int cgroup_fd;252 253 cgroup_fd = test__join_cgroup("/sockopt_sk");254 if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /sockopt_sk"))255 return;256 257 run_test(cgroup_fd);258 close(cgroup_fd);259}260