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