linux/tools/testing/selftests/bpf/test_sockopt_sk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <errno.h>
   4#include <stdio.h>
   5#include <unistd.h>
   6#include <sys/types.h>
   7#include <sys/socket.h>
   8#include <netinet/in.h>
   9
  10#include <linux/filter.h>
  11#include <bpf/bpf.h>
  12#include <bpf/libbpf.h>
  13
  14#include "bpf_rlimit.h"
  15#include "bpf_util.h"
  16#include "cgroup_helpers.h"
  17
  18#define CG_PATH                         "/sockopt"
  19
  20#define SOL_CUSTOM                      0xdeadbeef
  21
  22static int getsetsockopt(void)
  23{
  24        int fd, err;
  25        union {
  26                char u8[4];
  27                __u32 u32;
  28        } buf = {};
  29        socklen_t optlen;
  30
  31        fd = socket(AF_INET, SOCK_STREAM, 0);
  32        if (fd < 0) {
  33                log_err("Failed to create socket");
  34                return -1;
  35        }
  36
  37        /* IP_TOS - BPF bypass */
  38
  39        buf.u8[0] = 0x08;
  40        err = setsockopt(fd, SOL_IP, IP_TOS, &buf, 1);
  41        if (err) {
  42                log_err("Failed to call setsockopt(IP_TOS)");
  43                goto err;
  44        }
  45
  46        buf.u8[0] = 0x00;
  47        optlen = 1;
  48        err = getsockopt(fd, SOL_IP, IP_TOS, &buf, &optlen);
  49        if (err) {
  50                log_err("Failed to call getsockopt(IP_TOS)");
  51                goto err;
  52        }
  53
  54        if (buf.u8[0] != 0x08) {
  55                log_err("Unexpected getsockopt(IP_TOS) buf[0] 0x%02x != 0x08",
  56                        buf.u8[0]);
  57                goto err;
  58        }
  59
  60        /* IP_TTL - EPERM */
  61
  62        buf.u8[0] = 1;
  63        err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1);
  64        if (!err || errno != EPERM) {
  65                log_err("Unexpected success from setsockopt(IP_TTL)");
  66                goto err;
  67        }
  68
  69        /* SOL_CUSTOM - handled by BPF */
  70
  71        buf.u8[0] = 0x01;
  72        err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1);
  73        if (err) {
  74                log_err("Failed to call setsockopt");
  75                goto err;
  76        }
  77
  78        buf.u32 = 0x00;
  79        optlen = 4;
  80        err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen);
  81        if (err) {
  82                log_err("Failed to call getsockopt");
  83                goto err;
  84        }
  85
  86        if (optlen != 1) {
  87                log_err("Unexpected optlen %d != 1", optlen);
  88                goto err;
  89        }
  90        if (buf.u8[0] != 0x01) {
  91                log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]);
  92                goto err;
  93        }
  94
  95        /* SO_SNDBUF is overwritten */
  96
  97        buf.u32 = 0x01010101;
  98        err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4);
  99        if (err) {
 100                log_err("Failed to call setsockopt(SO_SNDBUF)");
 101                goto err;
 102        }
 103
 104        buf.u32 = 0x00;
 105        optlen = 4;
 106        err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen);
 107        if (err) {
 108                log_err("Failed to call getsockopt(SO_SNDBUF)");
 109                goto err;
 110        }
 111
 112        if (buf.u32 != 0x55AA*2) {
 113                log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2",
 114                        buf.u32);
 115                goto err;
 116        }
 117
 118        close(fd);
 119        return 0;
 120err:
 121        close(fd);
 122        return -1;
 123}
 124
 125static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
 126{
 127        enum bpf_attach_type attach_type;
 128        enum bpf_prog_type prog_type;
 129        struct bpf_program *prog;
 130        int err;
 131
 132        err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
 133        if (err) {
 134                log_err("Failed to deduct types for %s BPF program", title);
 135                return -1;
 136        }
 137
 138        prog = bpf_object__find_program_by_title(obj, title);
 139        if (!prog) {
 140                log_err("Failed to find %s BPF program", title);
 141                return -1;
 142        }
 143
 144        err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
 145                              attach_type, 0);
 146        if (err) {
 147                log_err("Failed to attach %s BPF program", title);
 148                return -1;
 149        }
 150
 151        return 0;
 152}
 153
 154static int run_test(int cgroup_fd)
 155{
 156        struct bpf_prog_load_attr attr = {
 157                .file = "./sockopt_sk.o",
 158        };
 159        struct bpf_object *obj;
 160        int ignored;
 161        int err;
 162
 163        err = bpf_prog_load_xattr(&attr, &obj, &ignored);
 164        if (err) {
 165                log_err("Failed to load BPF object");
 166                return -1;
 167        }
 168
 169        err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt");
 170        if (err)
 171                goto close_bpf_object;
 172
 173        err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt");
 174        if (err)
 175                goto close_bpf_object;
 176
 177        err = getsetsockopt();
 178
 179close_bpf_object:
 180        bpf_object__close(obj);
 181        return err;
 182}
 183
 184int main(int args, char **argv)
 185{
 186        int cgroup_fd;
 187        int err = EXIT_SUCCESS;
 188
 189        if (setup_cgroup_environment())
 190                goto cleanup_obj;
 191
 192        cgroup_fd = create_and_get_cgroup(CG_PATH);
 193        if (cgroup_fd < 0)
 194                goto cleanup_cgroup_env;
 195
 196        if (join_cgroup(CG_PATH))
 197                goto cleanup_cgroup;
 198
 199        if (run_test(cgroup_fd))
 200                err = EXIT_FAILURE;
 201
 202        printf("test_sockopt_sk: %s\n",
 203               err == EXIT_SUCCESS ? "PASSED" : "FAILED");
 204
 205cleanup_cgroup:
 206        close(cgroup_fd);
 207cleanup_cgroup_env:
 208        cleanup_cgroup_environment();
 209cleanup_obj:
 210        return err;
 211}
 212