linux/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <test_progs.h>
   3#include "cgroup_helpers.h"
   4
   5static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title)
   6{
   7        enum bpf_attach_type attach_type;
   8        enum bpf_prog_type prog_type;
   9        struct bpf_program *prog;
  10        int err;
  11
  12        err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
  13        if (err) {
  14                log_err("Failed to deduct types for %s BPF program", title);
  15                return -1;
  16        }
  17
  18        prog = bpf_object__find_program_by_title(obj, title);
  19        if (!prog) {
  20                log_err("Failed to find %s BPF program", title);
  21                return -1;
  22        }
  23
  24        err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
  25                              attach_type, BPF_F_ALLOW_MULTI);
  26        if (err) {
  27                log_err("Failed to attach %s BPF program", title);
  28                return -1;
  29        }
  30
  31        return 0;
  32}
  33
  34static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title)
  35{
  36        enum bpf_attach_type attach_type;
  37        enum bpf_prog_type prog_type;
  38        struct bpf_program *prog;
  39        int err;
  40
  41        err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
  42        if (err)
  43                return -1;
  44
  45        prog = bpf_object__find_program_by_title(obj, title);
  46        if (!prog)
  47                return -1;
  48
  49        err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd,
  50                               attach_type);
  51        if (err)
  52                return -1;
  53
  54        return 0;
  55}
  56
  57static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
  58                               int cg_child, int sock_fd)
  59{
  60        socklen_t optlen;
  61        __u8 buf;
  62        int err;
  63
  64        /* Set IP_TOS to the expected value (0x80). */
  65
  66        buf = 0x80;
  67        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
  68        if (err < 0) {
  69                log_err("Failed to call setsockopt(IP_TOS)");
  70                goto detach;
  71        }
  72
  73        buf = 0x00;
  74        optlen = 1;
  75        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
  76        if (err) {
  77                log_err("Failed to call getsockopt(IP_TOS)");
  78                goto detach;
  79        }
  80
  81        if (buf != 0x80) {
  82                log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf);
  83                err = -1;
  84                goto detach;
  85        }
  86
  87        /* Attach child program and make sure it returns new value:
  88         * - kernel:      -> 0x80
  89         * - child:  0x80 -> 0x90
  90         */
  91
  92        err = prog_attach(obj, cg_child, "cgroup/getsockopt/child");
  93        if (err)
  94                goto detach;
  95
  96        buf = 0x00;
  97        optlen = 1;
  98        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
  99        if (err) {
 100                log_err("Failed to call getsockopt(IP_TOS)");
 101                goto detach;
 102        }
 103
 104        if (buf != 0x90) {
 105                log_err("Unexpected getsockopt 0x%x != 0x90", buf);
 106                err = -1;
 107                goto detach;
 108        }
 109
 110        /* Attach parent program and make sure it returns new value:
 111         * - kernel:      -> 0x80
 112         * - child:  0x80 -> 0x90
 113         * - parent: 0x90 -> 0xA0
 114         */
 115
 116        err = prog_attach(obj, cg_parent, "cgroup/getsockopt/parent");
 117        if (err)
 118                goto detach;
 119
 120        buf = 0x00;
 121        optlen = 1;
 122        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 123        if (err) {
 124                log_err("Failed to call getsockopt(IP_TOS)");
 125                goto detach;
 126        }
 127
 128        if (buf != 0xA0) {
 129                log_err("Unexpected getsockopt 0x%x != 0xA0", buf);
 130                err = -1;
 131                goto detach;
 132        }
 133
 134        /* Setting unexpected initial sockopt should return EPERM:
 135         * - kernel: -> 0x40
 136         * - child:  unexpected 0x40, EPERM
 137         * - parent: unexpected 0x40, EPERM
 138         */
 139
 140        buf = 0x40;
 141        if (setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1) < 0) {
 142                log_err("Failed to call setsockopt(IP_TOS)");
 143                goto detach;
 144        }
 145
 146        buf = 0x00;
 147        optlen = 1;
 148        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 149        if (!err) {
 150                log_err("Unexpected success from getsockopt(IP_TOS)");
 151                goto detach;
 152        }
 153
 154        /* Detach child program and make sure we still get EPERM:
 155         * - kernel: -> 0x40
 156         * - parent: unexpected 0x40, EPERM
 157         */
 158
 159        err = prog_detach(obj, cg_child, "cgroup/getsockopt/child");
 160        if (err) {
 161                log_err("Failed to detach child program");
 162                goto detach;
 163        }
 164
 165        buf = 0x00;
 166        optlen = 1;
 167        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 168        if (!err) {
 169                log_err("Unexpected success from getsockopt(IP_TOS)");
 170                goto detach;
 171        }
 172
 173        /* Set initial value to the one the parent program expects:
 174         * - kernel:      -> 0x90
 175         * - parent: 0x90 -> 0xA0
 176         */
 177
 178        buf = 0x90;
 179        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 180        if (err < 0) {
 181                log_err("Failed to call setsockopt(IP_TOS)");
 182                goto detach;
 183        }
 184
 185        buf = 0x00;
 186        optlen = 1;
 187        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 188        if (err) {
 189                log_err("Failed to call getsockopt(IP_TOS)");
 190                goto detach;
 191        }
 192
 193        if (buf != 0xA0) {
 194                log_err("Unexpected getsockopt 0x%x != 0xA0", buf);
 195                err = -1;
 196                goto detach;
 197        }
 198
 199detach:
 200        prog_detach(obj, cg_child, "cgroup/getsockopt/child");
 201        prog_detach(obj, cg_parent, "cgroup/getsockopt/parent");
 202
 203        return err;
 204}
 205
 206static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
 207                               int cg_child, int sock_fd)
 208{
 209        socklen_t optlen;
 210        __u8 buf;
 211        int err;
 212
 213        /* Set IP_TOS to the expected value (0x80). */
 214
 215        buf = 0x80;
 216        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 217        if (err < 0) {
 218                log_err("Failed to call setsockopt(IP_TOS)");
 219                goto detach;
 220        }
 221
 222        buf = 0x00;
 223        optlen = 1;
 224        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 225        if (err) {
 226                log_err("Failed to call getsockopt(IP_TOS)");
 227                goto detach;
 228        }
 229
 230        if (buf != 0x80) {
 231                log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf);
 232                err = -1;
 233                goto detach;
 234        }
 235
 236        /* Attach child program and make sure it adds 0x10. */
 237
 238        err = prog_attach(obj, cg_child, "cgroup/setsockopt");
 239        if (err)
 240                goto detach;
 241
 242        buf = 0x80;
 243        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 244        if (err < 0) {
 245                log_err("Failed to call setsockopt(IP_TOS)");
 246                goto detach;
 247        }
 248
 249        buf = 0x00;
 250        optlen = 1;
 251        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 252        if (err) {
 253                log_err("Failed to call getsockopt(IP_TOS)");
 254                goto detach;
 255        }
 256
 257        if (buf != 0x80 + 0x10) {
 258                log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf);
 259                err = -1;
 260                goto detach;
 261        }
 262
 263        /* Attach parent program and make sure it adds another 0x10. */
 264
 265        err = prog_attach(obj, cg_parent, "cgroup/setsockopt");
 266        if (err)
 267                goto detach;
 268
 269        buf = 0x80;
 270        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 271        if (err < 0) {
 272                log_err("Failed to call setsockopt(IP_TOS)");
 273                goto detach;
 274        }
 275
 276        buf = 0x00;
 277        optlen = 1;
 278        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 279        if (err) {
 280                log_err("Failed to call getsockopt(IP_TOS)");
 281                goto detach;
 282        }
 283
 284        if (buf != 0x80 + 2 * 0x10) {
 285                log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf);
 286                err = -1;
 287                goto detach;
 288        }
 289
 290detach:
 291        prog_detach(obj, cg_child, "cgroup/setsockopt");
 292        prog_detach(obj, cg_parent, "cgroup/setsockopt");
 293
 294        return err;
 295}
 296
 297void test_sockopt_multi(void)
 298{
 299        struct bpf_prog_load_attr attr = {
 300                .file = "./sockopt_multi.o",
 301        };
 302        int cg_parent = -1, cg_child = -1;
 303        struct bpf_object *obj = NULL;
 304        int sock_fd = -1;
 305        int err = -1;
 306        int ignored;
 307
 308        cg_parent = test__join_cgroup("/parent");
 309        if (CHECK_FAIL(cg_parent < 0))
 310                goto out;
 311
 312        cg_child = test__join_cgroup("/parent/child");
 313        if (CHECK_FAIL(cg_child < 0))
 314                goto out;
 315
 316        err = bpf_prog_load_xattr(&attr, &obj, &ignored);
 317        if (CHECK_FAIL(err))
 318                goto out;
 319
 320        sock_fd = socket(AF_INET, SOCK_STREAM, 0);
 321        if (CHECK_FAIL(sock_fd < 0))
 322                goto out;
 323
 324        CHECK_FAIL(run_getsockopt_test(obj, cg_parent, cg_child, sock_fd));
 325        CHECK_FAIL(run_setsockopt_test(obj, cg_parent, cg_child, sock_fd));
 326
 327out:
 328        close(sock_fd);
 329        bpf_object__close(obj);
 330        close(cg_child);
 331        close(cg_parent);
 332}
 333