Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 /*
0004  * Copyright 2021 Google LLC.
0005  */
0006 
0007 #include <test_progs.h>
0008 #include <cgroup_helpers.h>
0009 #include <network_helpers.h>
0010 
0011 #include "cgroup_getset_retval_setsockopt.skel.h"
0012 #include "cgroup_getset_retval_getsockopt.skel.h"
0013 
0014 #define SOL_CUSTOM  0xdeadbeef
0015 
0016 static int zero;
0017 
0018 static void test_setsockopt_set(int cgroup_fd, int sock_fd)
0019 {
0020     struct cgroup_getset_retval_setsockopt *obj;
0021     struct bpf_link *link_set_eunatch = NULL;
0022 
0023     obj = cgroup_getset_retval_setsockopt__open_and_load();
0024     if (!ASSERT_OK_PTR(obj, "skel-load"))
0025         return;
0026 
0027     /* Attach setsockopt that sets EUNATCH, assert that
0028      * we actually get that error when we run setsockopt()
0029      */
0030     link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
0031                               cgroup_fd);
0032     if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
0033         goto close_bpf_object;
0034 
0035     if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
0036                    &zero, sizeof(int)), "setsockopt"))
0037         goto close_bpf_object;
0038     if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
0039         goto close_bpf_object;
0040 
0041     if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
0042         goto close_bpf_object;
0043     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0044         goto close_bpf_object;
0045 
0046 close_bpf_object:
0047     bpf_link__destroy(link_set_eunatch);
0048 
0049     cgroup_getset_retval_setsockopt__destroy(obj);
0050 }
0051 
0052 static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd)
0053 {
0054     struct cgroup_getset_retval_setsockopt *obj;
0055     struct bpf_link *link_set_eunatch = NULL, *link_get_retval = NULL;
0056 
0057     obj = cgroup_getset_retval_setsockopt__open_and_load();
0058     if (!ASSERT_OK_PTR(obj, "skel-load"))
0059         return;
0060 
0061     /* Attach setsockopt that sets EUNATCH, and one that gets the
0062      * previously set errno. Assert that we get the same errno back.
0063      */
0064     link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
0065                               cgroup_fd);
0066     if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
0067         goto close_bpf_object;
0068     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0069                              cgroup_fd);
0070     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0071         goto close_bpf_object;
0072 
0073     if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
0074                    &zero, sizeof(int)), "setsockopt"))
0075         goto close_bpf_object;
0076     if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
0077         goto close_bpf_object;
0078 
0079     if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
0080         goto close_bpf_object;
0081     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0082         goto close_bpf_object;
0083     if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))
0084         goto close_bpf_object;
0085 
0086 close_bpf_object:
0087     bpf_link__destroy(link_set_eunatch);
0088     bpf_link__destroy(link_get_retval);
0089 
0090     cgroup_getset_retval_setsockopt__destroy(obj);
0091 }
0092 
0093 static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd)
0094 {
0095     struct cgroup_getset_retval_setsockopt *obj;
0096     struct bpf_link *link_get_retval = NULL;
0097 
0098     obj = cgroup_getset_retval_setsockopt__open_and_load();
0099     if (!ASSERT_OK_PTR(obj, "skel-load"))
0100         return;
0101 
0102     /* Attach setsockopt that gets the previously set errno.
0103      * Assert that, without anything setting one, we get 0.
0104      */
0105     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0106                              cgroup_fd);
0107     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0108         goto close_bpf_object;
0109 
0110     if (!ASSERT_OK(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
0111                   &zero, sizeof(int)), "setsockopt"))
0112         goto close_bpf_object;
0113 
0114     if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
0115         goto close_bpf_object;
0116     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0117         goto close_bpf_object;
0118     if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
0119         goto close_bpf_object;
0120 
0121 close_bpf_object:
0122     bpf_link__destroy(link_get_retval);
0123 
0124     cgroup_getset_retval_setsockopt__destroy(obj);
0125 }
0126 
0127 static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd)
0128 {
0129     struct cgroup_getset_retval_setsockopt *obj;
0130     struct bpf_link *link_get_retval = NULL, *link_set_eunatch = NULL;
0131 
0132     obj = cgroup_getset_retval_setsockopt__open_and_load();
0133     if (!ASSERT_OK_PTR(obj, "skel-load"))
0134         return;
0135 
0136     /* Attach setsockopt that gets the previously set errno, and then
0137      * one that sets the errno to EUNATCH. Assert that the get does not
0138      * see EUNATCH set later, and does not prevent EUNATCH from being set.
0139      */
0140     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0141                              cgroup_fd);
0142     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0143         goto close_bpf_object;
0144     link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
0145                               cgroup_fd);
0146     if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
0147         goto close_bpf_object;
0148 
0149     if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
0150                    &zero, sizeof(int)), "setsockopt"))
0151         goto close_bpf_object;
0152     if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
0153         goto close_bpf_object;
0154 
0155     if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
0156         goto close_bpf_object;
0157     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0158         goto close_bpf_object;
0159     if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
0160         goto close_bpf_object;
0161 
0162 close_bpf_object:
0163     bpf_link__destroy(link_get_retval);
0164     bpf_link__destroy(link_set_eunatch);
0165 
0166     cgroup_getset_retval_setsockopt__destroy(obj);
0167 }
0168 
0169 static void test_setsockopt_override(int cgroup_fd, int sock_fd)
0170 {
0171     struct cgroup_getset_retval_setsockopt *obj;
0172     struct bpf_link *link_set_eunatch = NULL, *link_set_eisconn = NULL;
0173     struct bpf_link *link_get_retval = NULL;
0174 
0175     obj = cgroup_getset_retval_setsockopt__open_and_load();
0176     if (!ASSERT_OK_PTR(obj, "skel-load"))
0177         return;
0178 
0179     /* Attach setsockopt that sets EUNATCH, then one that sets EISCONN,
0180      * and then one that gets the exported errno. Assert both the syscall
0181      * and the helper sees the last set errno.
0182      */
0183     link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
0184                               cgroup_fd);
0185     if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
0186         goto close_bpf_object;
0187     link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
0188                               cgroup_fd);
0189     if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
0190         goto close_bpf_object;
0191     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0192                              cgroup_fd);
0193     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0194         goto close_bpf_object;
0195 
0196     if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
0197                    &zero, sizeof(int)), "setsockopt"))
0198         goto close_bpf_object;
0199     if (!ASSERT_EQ(errno, EISCONN, "setsockopt-errno"))
0200         goto close_bpf_object;
0201 
0202     if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
0203         goto close_bpf_object;
0204     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0205         goto close_bpf_object;
0206     if (!ASSERT_EQ(obj->bss->retval_value, -EISCONN, "retval_value"))
0207         goto close_bpf_object;
0208 
0209 close_bpf_object:
0210     bpf_link__destroy(link_set_eunatch);
0211     bpf_link__destroy(link_set_eisconn);
0212     bpf_link__destroy(link_get_retval);
0213 
0214     cgroup_getset_retval_setsockopt__destroy(obj);
0215 }
0216 
0217 static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd)
0218 {
0219     struct cgroup_getset_retval_setsockopt *obj;
0220     struct bpf_link *link_legacy_eperm = NULL, *link_get_retval = NULL;
0221 
0222     obj = cgroup_getset_retval_setsockopt__open_and_load();
0223     if (!ASSERT_OK_PTR(obj, "skel-load"))
0224         return;
0225 
0226     /* Attach setsockopt that return a reject without setting errno
0227      * (legacy reject), and one that gets the errno. Assert that for
0228      * backward compatibility the syscall result in EPERM, and this
0229      * is also visible to the helper.
0230      */
0231     link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,
0232                                cgroup_fd);
0233     if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))
0234         goto close_bpf_object;
0235     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0236                              cgroup_fd);
0237     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0238         goto close_bpf_object;
0239 
0240     if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
0241                    &zero, sizeof(int)), "setsockopt"))
0242         goto close_bpf_object;
0243     if (!ASSERT_EQ(errno, EPERM, "setsockopt-errno"))
0244         goto close_bpf_object;
0245 
0246     if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
0247         goto close_bpf_object;
0248     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0249         goto close_bpf_object;
0250     if (!ASSERT_EQ(obj->bss->retval_value, -EPERM, "retval_value"))
0251         goto close_bpf_object;
0252 
0253 close_bpf_object:
0254     bpf_link__destroy(link_legacy_eperm);
0255     bpf_link__destroy(link_get_retval);
0256 
0257     cgroup_getset_retval_setsockopt__destroy(obj);
0258 }
0259 
0260 static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd)
0261 {
0262     struct cgroup_getset_retval_setsockopt *obj;
0263     struct bpf_link *link_set_eunatch = NULL, *link_legacy_eperm = NULL;
0264     struct bpf_link *link_get_retval = NULL;
0265 
0266     obj = cgroup_getset_retval_setsockopt__open_and_load();
0267     if (!ASSERT_OK_PTR(obj, "skel-load"))
0268         return;
0269 
0270     /* Attach setsockopt that sets EUNATCH, then one that return a reject
0271      * without setting errno, and then one that gets the exported errno.
0272      * Assert both the syscall and the helper's errno are unaffected by
0273      * the second prog (i.e. legacy rejects does not override the errno
0274      * to EPERM).
0275      */
0276     link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
0277                               cgroup_fd);
0278     if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
0279         goto close_bpf_object;
0280     link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,
0281                                cgroup_fd);
0282     if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))
0283         goto close_bpf_object;
0284     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0285                              cgroup_fd);
0286     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0287         goto close_bpf_object;
0288 
0289     if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
0290                    &zero, sizeof(int)), "setsockopt"))
0291         goto close_bpf_object;
0292     if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
0293         goto close_bpf_object;
0294 
0295     if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
0296         goto close_bpf_object;
0297     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0298         goto close_bpf_object;
0299     if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))
0300         goto close_bpf_object;
0301 
0302 close_bpf_object:
0303     bpf_link__destroy(link_set_eunatch);
0304     bpf_link__destroy(link_legacy_eperm);
0305     bpf_link__destroy(link_get_retval);
0306 
0307     cgroup_getset_retval_setsockopt__destroy(obj);
0308 }
0309 
0310 static void test_getsockopt_get(int cgroup_fd, int sock_fd)
0311 {
0312     struct cgroup_getset_retval_getsockopt *obj;
0313     struct bpf_link *link_get_retval = NULL;
0314     int buf;
0315     socklen_t optlen = sizeof(buf);
0316 
0317     obj = cgroup_getset_retval_getsockopt__open_and_load();
0318     if (!ASSERT_OK_PTR(obj, "skel-load"))
0319         return;
0320 
0321     /* Attach getsockopt that gets previously set errno. Assert that the
0322      * error from kernel is in both ctx_retval_value and retval_value.
0323      */
0324     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0325                              cgroup_fd);
0326     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0327         goto close_bpf_object;
0328 
0329     if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,
0330                    &buf, &optlen), "getsockopt"))
0331         goto close_bpf_object;
0332     if (!ASSERT_EQ(errno, EOPNOTSUPP, "getsockopt-errno"))
0333         goto close_bpf_object;
0334 
0335     if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
0336         goto close_bpf_object;
0337     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0338         goto close_bpf_object;
0339     if (!ASSERT_EQ(obj->bss->retval_value, -EOPNOTSUPP, "retval_value"))
0340         goto close_bpf_object;
0341     if (!ASSERT_EQ(obj->bss->ctx_retval_value, -EOPNOTSUPP, "ctx_retval_value"))
0342         goto close_bpf_object;
0343 
0344 close_bpf_object:
0345     bpf_link__destroy(link_get_retval);
0346 
0347     cgroup_getset_retval_getsockopt__destroy(obj);
0348 }
0349 
0350 static void test_getsockopt_override(int cgroup_fd, int sock_fd)
0351 {
0352     struct cgroup_getset_retval_getsockopt *obj;
0353     struct bpf_link *link_set_eisconn = NULL;
0354     int buf;
0355     socklen_t optlen = sizeof(buf);
0356 
0357     obj = cgroup_getset_retval_getsockopt__open_and_load();
0358     if (!ASSERT_OK_PTR(obj, "skel-load"))
0359         return;
0360 
0361     /* Attach getsockopt that sets retval to -EISCONN. Assert that this
0362      * overrides the value from kernel.
0363      */
0364     link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
0365                               cgroup_fd);
0366     if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
0367         goto close_bpf_object;
0368 
0369     if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,
0370                    &buf, &optlen), "getsockopt"))
0371         goto close_bpf_object;
0372     if (!ASSERT_EQ(errno, EISCONN, "getsockopt-errno"))
0373         goto close_bpf_object;
0374 
0375     if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
0376         goto close_bpf_object;
0377     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0378         goto close_bpf_object;
0379 
0380 close_bpf_object:
0381     bpf_link__destroy(link_set_eisconn);
0382 
0383     cgroup_getset_retval_getsockopt__destroy(obj);
0384 }
0385 
0386 static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd)
0387 {
0388     struct cgroup_getset_retval_getsockopt *obj;
0389     struct bpf_link *link_set_eisconn = NULL, *link_clear_retval = NULL;
0390     struct bpf_link *link_get_retval = NULL;
0391     int buf;
0392     socklen_t optlen = sizeof(buf);
0393 
0394     obj = cgroup_getset_retval_getsockopt__open_and_load();
0395     if (!ASSERT_OK_PTR(obj, "skel-load"))
0396         return;
0397 
0398     /* Attach getsockopt that sets retval to -EISCONN, and one that clears
0399      * ctx retval. Assert that the clearing ctx retval is synced to helper
0400      * and clears any errors both from kernel and BPF..
0401      */
0402     link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
0403                               cgroup_fd);
0404     if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
0405         goto close_bpf_object;
0406     link_clear_retval = bpf_program__attach_cgroup(obj->progs.clear_retval,
0407                                cgroup_fd);
0408     if (!ASSERT_OK_PTR(link_clear_retval, "cg-attach-clear_retval"))
0409         goto close_bpf_object;
0410     link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
0411                              cgroup_fd);
0412     if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
0413         goto close_bpf_object;
0414 
0415     if (!ASSERT_OK(getsockopt(sock_fd, SOL_CUSTOM, 0,
0416                   &buf, &optlen), "getsockopt"))
0417         goto close_bpf_object;
0418 
0419     if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
0420         goto close_bpf_object;
0421     if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
0422         goto close_bpf_object;
0423     if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
0424         goto close_bpf_object;
0425     if (!ASSERT_EQ(obj->bss->ctx_retval_value, 0, "ctx_retval_value"))
0426         goto close_bpf_object;
0427 
0428 close_bpf_object:
0429     bpf_link__destroy(link_set_eisconn);
0430     bpf_link__destroy(link_clear_retval);
0431     bpf_link__destroy(link_get_retval);
0432 
0433     cgroup_getset_retval_getsockopt__destroy(obj);
0434 }
0435 
0436 void test_cgroup_getset_retval(void)
0437 {
0438     int cgroup_fd = -1;
0439     int sock_fd = -1;
0440 
0441     cgroup_fd = test__join_cgroup("/cgroup_getset_retval");
0442     if (!ASSERT_GE(cgroup_fd, 0, "cg-create"))
0443         goto close_fd;
0444 
0445     sock_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
0446     if (!ASSERT_GE(sock_fd, 0, "start-server"))
0447         goto close_fd;
0448 
0449     if (test__start_subtest("setsockopt-set"))
0450         test_setsockopt_set(cgroup_fd, sock_fd);
0451 
0452     if (test__start_subtest("setsockopt-set_and_get"))
0453         test_setsockopt_set_and_get(cgroup_fd, sock_fd);
0454 
0455     if (test__start_subtest("setsockopt-default_zero"))
0456         test_setsockopt_default_zero(cgroup_fd, sock_fd);
0457 
0458     if (test__start_subtest("setsockopt-default_zero_and_set"))
0459         test_setsockopt_default_zero_and_set(cgroup_fd, sock_fd);
0460 
0461     if (test__start_subtest("setsockopt-override"))
0462         test_setsockopt_override(cgroup_fd, sock_fd);
0463 
0464     if (test__start_subtest("setsockopt-legacy_eperm"))
0465         test_setsockopt_legacy_eperm(cgroup_fd, sock_fd);
0466 
0467     if (test__start_subtest("setsockopt-legacy_no_override"))
0468         test_setsockopt_legacy_no_override(cgroup_fd, sock_fd);
0469 
0470     if (test__start_subtest("getsockopt-get"))
0471         test_getsockopt_get(cgroup_fd, sock_fd);
0472 
0473     if (test__start_subtest("getsockopt-override"))
0474         test_getsockopt_override(cgroup_fd, sock_fd);
0475 
0476     if (test__start_subtest("getsockopt-retval_sync"))
0477         test_getsockopt_retval_sync(cgroup_fd, sock_fd);
0478 
0479 close_fd:
0480     close(cgroup_fd);
0481 }