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        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 142        if (err < 0) {
 143                log_err("Failed to call setsockopt(IP_TOS)");
 144                goto detach;
 145        }
 146
 147        buf = 0x00;
 148        optlen = 1;
 149        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 150        if (!err) {
 151                log_err("Unexpected success from getsockopt(IP_TOS)");
 152                goto detach;
 153        }
 154
 155        /* Detach child program and make sure we still get EPERM:
 156         * - kernel: -> 0x40
 157         * - parent: unexpected 0x40, EPERM
 158         */
 159
 160        err = prog_detach(obj, cg_child, "cgroup/getsockopt/child");
 161        if (err) {
 162                log_err("Failed to detach child program");
 163                goto detach;
 164        }
 165
 166        buf = 0x00;
 167        optlen = 1;
 168        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 169        if (!err) {
 170                log_err("Unexpected success from getsockopt(IP_TOS)");
 171                goto detach;
 172        }
 173
 174        /* Set initial value to the one the parent program expects:
 175         * - kernel:      -> 0x90
 176         * - parent: 0x90 -> 0xA0
 177         */
 178
 179        buf = 0x90;
 180        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 181        if (err < 0) {
 182                log_err("Failed to call setsockopt(IP_TOS)");
 183                goto detach;
 184        }
 185
 186        buf = 0x00;
 187        optlen = 1;
 188        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 189        if (err) {
 190                log_err("Failed to call getsockopt(IP_TOS)");
 191                goto detach;
 192        }
 193
 194        if (buf != 0xA0) {
 195                log_err("Unexpected getsockopt 0x%x != 0xA0", buf);
 196                err = -1;
 197                goto detach;
 198        }
 199
 200detach:
 201        prog_detach(obj, cg_child, "cgroup/getsockopt/child");
 202        prog_detach(obj, cg_parent, "cgroup/getsockopt/parent");
 203
 204        return err;
 205}
 206
 207static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
 208                               int cg_child, int sock_fd)
 209{
 210        socklen_t optlen;
 211        __u8 buf;
 212        int err;
 213
 214        /* Set IP_TOS to the expected value (0x80). */
 215
 216        buf = 0x80;
 217        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 218        if (err < 0) {
 219                log_err("Failed to call setsockopt(IP_TOS)");
 220                goto detach;
 221        }
 222
 223        buf = 0x00;
 224        optlen = 1;
 225        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 226        if (err) {
 227                log_err("Failed to call getsockopt(IP_TOS)");
 228                goto detach;
 229        }
 230
 231        if (buf != 0x80) {
 232                log_err("Unexpected getsockopt 0x%x != 0x80 without BPF", buf);
 233                err = -1;
 234                goto detach;
 235        }
 236
 237        /* Attach child program and make sure it adds 0x10. */
 238
 239        err = prog_attach(obj, cg_child, "cgroup/setsockopt");
 240        if (err)
 241                goto detach;
 242
 243        buf = 0x80;
 244        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 245        if (err < 0) {
 246                log_err("Failed to call setsockopt(IP_TOS)");
 247                goto detach;
 248        }
 249
 250        buf = 0x00;
 251        optlen = 1;
 252        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 253        if (err) {
 254                log_err("Failed to call getsockopt(IP_TOS)");
 255                goto detach;
 256        }
 257
 258        if (buf != 0x80 + 0x10) {
 259                log_err("Unexpected getsockopt 0x%x != 0x80 + 0x10", buf);
 260                err = -1;
 261                goto detach;
 262        }
 263
 264        /* Attach parent program and make sure it adds another 0x10. */
 265
 266        err = prog_attach(obj, cg_parent, "cgroup/setsockopt");
 267        if (err)
 268                goto detach;
 269
 270        buf = 0x80;
 271        err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
 272        if (err < 0) {
 273                log_err("Failed to call setsockopt(IP_TOS)");
 274                goto detach;
 275        }
 276
 277        buf = 0x00;
 278        optlen = 1;
 279        err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
 280        if (err) {
 281                log_err("Failed to call getsockopt(IP_TOS)");
 282                goto detach;
 283        }
 284
 285        if (buf != 0x80 + 2 * 0x10) {
 286                log_err("Unexpected getsockopt 0x%x != 0x80 + 2 * 0x10", buf);
 287                err = -1;
 288                goto detach;
 289        }
 290
 291detach:
 292        prog_detach(obj, cg_child, "cgroup/setsockopt");
 293        prog_detach(obj, cg_parent, "cgroup/setsockopt");
 294
 295        return err;
 296}
 297
 298void test_sockopt_multi(void)
 299{
 300        struct bpf_prog_load_attr attr = {
 301                .file = "./sockopt_multi.o",
 302        };
 303        int cg_parent = -1, cg_child = -1;
 304        struct bpf_object *obj = NULL;
 305        int sock_fd = -1;
 306        int err = -1;
 307        int ignored;
 308
 309        cg_parent = test__join_cgroup("/parent");
 310        if (CHECK_FAIL(cg_parent < 0))
 311                goto out;
 312
 313        cg_child = test__join_cgroup("/parent/child");
 314        if (CHECK_FAIL(cg_child < 0))
 315                goto out;
 316
 317        err = bpf_prog_load_xattr(&attr, &obj, &ignored);
 318        if (CHECK_FAIL(err))
 319                goto out;
 320
 321        sock_fd = socket(AF_INET, SOCK_STREAM, 0);
 322        if (CHECK_FAIL(sock_fd < 0))
 323                goto out;
 324
 325        CHECK_FAIL(run_getsockopt_test(obj, cg_parent, cg_child, sock_fd));
 326        CHECK_FAIL(run_setsockopt_test(obj, cg_parent, cg_child, sock_fd));
 327
 328out:
 329        close(sock_fd);
 330        bpf_object__close(obj);
 331        close(cg_child);
 332        close(cg_parent);
 333}
 334