0001
0002
0003 #include <sys/types.h>
0004 #include <sys/socket.h>
0005 #include <test_progs.h>
0006 #include <bpf/btf.h>
0007
0008 #include "lsm_cgroup.skel.h"
0009 #include "lsm_cgroup_nonvoid.skel.h"
0010 #include "cgroup_helpers.h"
0011 #include "network_helpers.h"
0012
0013 #ifndef ENOTSUPP
0014 #define ENOTSUPP 524
0015 #endif
0016
0017 static struct btf *btf;
0018
0019 static __u32 query_prog_cnt(int cgroup_fd, const char *attach_func)
0020 {
0021 LIBBPF_OPTS(bpf_prog_query_opts, p);
0022 int cnt = 0;
0023 int i;
0024
0025 ASSERT_OK(bpf_prog_query_opts(cgroup_fd, BPF_LSM_CGROUP, &p), "prog_query");
0026
0027 if (!attach_func)
0028 return p.prog_cnt;
0029
0030
0031
0032
0033
0034 if (!btf)
0035 btf = btf__load_vmlinux_btf();
0036 if (!ASSERT_OK(libbpf_get_error(btf), "btf_vmlinux"))
0037 return -1;
0038
0039 p.prog_ids = malloc(sizeof(u32) * p.prog_cnt);
0040 p.prog_attach_flags = malloc(sizeof(u32) * p.prog_cnt);
0041 ASSERT_OK(bpf_prog_query_opts(cgroup_fd, BPF_LSM_CGROUP, &p), "prog_query");
0042
0043 for (i = 0; i < p.prog_cnt; i++) {
0044 struct bpf_prog_info info = {};
0045 __u32 info_len = sizeof(info);
0046 int fd;
0047
0048 fd = bpf_prog_get_fd_by_id(p.prog_ids[i]);
0049 ASSERT_GE(fd, 0, "prog_get_fd_by_id");
0050 ASSERT_OK(bpf_obj_get_info_by_fd(fd, &info, &info_len), "prog_info_by_fd");
0051 close(fd);
0052
0053 if (info.attach_btf_id ==
0054 btf__find_by_name_kind(btf, attach_func, BTF_KIND_FUNC))
0055 cnt++;
0056 }
0057
0058 free(p.prog_ids);
0059 free(p.prog_attach_flags);
0060
0061 return cnt;
0062 }
0063
0064 static void test_lsm_cgroup_functional(void)
0065 {
0066 DECLARE_LIBBPF_OPTS(bpf_prog_attach_opts, attach_opts);
0067 DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);
0068 int cgroup_fd = -1, cgroup_fd2 = -1, cgroup_fd3 = -1;
0069 int listen_fd, client_fd, accepted_fd;
0070 struct lsm_cgroup *skel = NULL;
0071 int post_create_prog_fd2 = -1;
0072 int post_create_prog_fd = -1;
0073 int bind_link_fd2 = -1;
0074 int bind_prog_fd2 = -1;
0075 int alloc_prog_fd = -1;
0076 int bind_prog_fd = -1;
0077 int bind_link_fd = -1;
0078 int clone_prog_fd = -1;
0079 int err, fd, prio;
0080 socklen_t socklen;
0081
0082 cgroup_fd3 = test__join_cgroup("/sock_policy_empty");
0083 if (!ASSERT_GE(cgroup_fd3, 0, "create empty cgroup"))
0084 goto close_cgroup;
0085
0086 cgroup_fd2 = test__join_cgroup("/sock_policy_reuse");
0087 if (!ASSERT_GE(cgroup_fd2, 0, "create cgroup for reuse"))
0088 goto close_cgroup;
0089
0090 cgroup_fd = test__join_cgroup("/sock_policy");
0091 if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
0092 goto close_cgroup;
0093
0094 skel = lsm_cgroup__open_and_load();
0095 if (!ASSERT_OK_PTR(skel, "open_and_load"))
0096 goto close_cgroup;
0097
0098 post_create_prog_fd = bpf_program__fd(skel->progs.socket_post_create);
0099 post_create_prog_fd2 = bpf_program__fd(skel->progs.socket_post_create2);
0100 bind_prog_fd = bpf_program__fd(skel->progs.socket_bind);
0101 bind_prog_fd2 = bpf_program__fd(skel->progs.socket_bind2);
0102 alloc_prog_fd = bpf_program__fd(skel->progs.socket_alloc);
0103 clone_prog_fd = bpf_program__fd(skel->progs.socket_clone);
0104
0105 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_sk_alloc_security"), 0, "prog count");
0106 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 0, "total prog count");
0107 err = bpf_prog_attach(alloc_prog_fd, cgroup_fd, BPF_LSM_CGROUP, 0);
0108 if (err == -ENOTSUPP) {
0109 test__skip();
0110 goto close_cgroup;
0111 }
0112 if (!ASSERT_OK(err, "attach alloc_prog_fd"))
0113 goto detach_cgroup;
0114 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_sk_alloc_security"), 1, "prog count");
0115 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 1, "total prog count");
0116
0117 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_inet_csk_clone"), 0, "prog count");
0118 err = bpf_prog_attach(clone_prog_fd, cgroup_fd, BPF_LSM_CGROUP, 0);
0119 if (!ASSERT_OK(err, "attach clone_prog_fd"))
0120 goto detach_cgroup;
0121 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_inet_csk_clone"), 1, "prog count");
0122 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 2, "total prog count");
0123
0124
0125
0126 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_socket_post_create"), 0, "prog count");
0127 err = bpf_prog_attach(post_create_prog_fd, cgroup_fd,
0128 BPF_LSM_CGROUP, 0);
0129 if (!ASSERT_OK(err, "attach post_create_prog_fd"))
0130 goto detach_cgroup;
0131 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_socket_post_create"), 1, "prog count");
0132 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 3, "total prog count");
0133
0134 attach_opts.replace_prog_fd = post_create_prog_fd;
0135 err = bpf_prog_attach_opts(post_create_prog_fd2, cgroup_fd,
0136 BPF_LSM_CGROUP, &attach_opts);
0137 if (!ASSERT_OK(err, "prog replace post_create_prog_fd"))
0138 goto detach_cgroup;
0139 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_socket_post_create"), 1, "prog count");
0140 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 3, "total prog count");
0141
0142
0143
0144 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_socket_bind"), 0, "prog count");
0145 bind_link_fd = bpf_link_create(bind_prog_fd, cgroup_fd,
0146 BPF_LSM_CGROUP, NULL);
0147 if (!ASSERT_GE(bind_link_fd, 0, "link create bind_prog_fd"))
0148 goto detach_cgroup;
0149 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_socket_bind"), 1, "prog count");
0150 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 4, "total prog count");
0151
0152 update_opts.old_prog_fd = bind_prog_fd;
0153 update_opts.flags = BPF_F_REPLACE;
0154
0155 err = bpf_link_update(bind_link_fd, bind_prog_fd2, &update_opts);
0156 if (!ASSERT_OK(err, "link update bind_prog_fd"))
0157 goto detach_cgroup;
0158 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_socket_bind"), 1, "prog count");
0159 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 4, "total prog count");
0160
0161
0162
0163
0164
0165
0166 ASSERT_EQ(query_prog_cnt(cgroup_fd, "bpf_lsm_socket_bind"), 1, "prog count");
0167 ASSERT_EQ(query_prog_cnt(cgroup_fd2, "bpf_lsm_socket_bind"), 0, "prog count");
0168 bind_link_fd2 = bpf_link_create(bind_prog_fd2, cgroup_fd2,
0169 BPF_LSM_CGROUP, NULL);
0170 if (!ASSERT_GE(bind_link_fd2, 0, "link create bind_prog_fd2"))
0171 goto detach_cgroup;
0172 ASSERT_EQ(query_prog_cnt(cgroup_fd2, "bpf_lsm_socket_bind"), 1, "prog count");
0173 ASSERT_EQ(query_prog_cnt(cgroup_fd, NULL), 4, "total prog count");
0174 ASSERT_EQ(query_prog_cnt(cgroup_fd2, NULL), 1, "total prog count");
0175
0176
0177
0178 fd = socket(AF_UNIX, SOCK_STREAM, 0);
0179 ASSERT_LT(fd, 0, "socket(AF_UNIX)");
0180 close(fd);
0181
0182
0183
0184 fd = socket(AF_INET6, SOCK_STREAM, 0);
0185 if (!ASSERT_GE(fd, 0, "socket(SOCK_STREAM)"))
0186 goto detach_cgroup;
0187
0188 prio = 0;
0189 socklen = sizeof(prio);
0190 ASSERT_GE(getsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio, &socklen), 0,
0191 "getsockopt");
0192 ASSERT_EQ(prio, 123, "sk_priority");
0193
0194 close(fd);
0195
0196
0197
0198 ASSERT_LT(socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)), 0,
0199 "socket(AF_PACKET, ..., ETH_P_ALL)");
0200
0201 fd = socket(AF_PACKET, SOCK_RAW, 0);
0202 ASSERT_GE(fd, 0, "socket(AF_PACKET, ..., 0)");
0203
0204
0205
0206 struct sockaddr_ll sa = {
0207 .sll_family = AF_PACKET,
0208 .sll_protocol = htons(ETH_P_ALL),
0209 };
0210 ASSERT_LT(bind(fd, (struct sockaddr *)&sa, sizeof(sa)), 0,
0211 "bind(ETH_P_ALL)");
0212
0213 close(fd);
0214
0215
0216
0217 listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
0218 ASSERT_GE(listen_fd, 0, "start_server");
0219 client_fd = connect_to_fd(listen_fd, 0);
0220 ASSERT_GE(client_fd, 0, "connect_to_fd");
0221 accepted_fd = accept(listen_fd, NULL, NULL);
0222 ASSERT_GE(accepted_fd, 0, "accept");
0223
0224 prio = 0;
0225 socklen = sizeof(prio);
0226 ASSERT_GE(getsockopt(accepted_fd, SOL_SOCKET, SO_PRIORITY, &prio, &socklen), 0,
0227 "getsockopt");
0228 ASSERT_EQ(prio, 234, "sk_priority");
0229
0230
0231 ASSERT_EQ(skel->bss->called_socket_post_create, 0, "called_create");
0232 ASSERT_EQ(skel->bss->called_socket_bind, 0, "called_bind");
0233
0234
0235
0236
0237
0238
0239
0240 ASSERT_EQ(skel->bss->called_socket_post_create2, 5, "called_create2");
0241
0242
0243
0244
0245 ASSERT_EQ(skel->bss->called_socket_bind2, 2, "called_bind2");
0246
0247 ASSERT_EQ(skel->bss->called_socket_clone, 1, "called_clone");
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257 ASSERT_EQ(skel->bss->called_socket_alloc, 7, "called_alloc");
0258
0259 close(listen_fd);
0260 close(client_fd);
0261 close(accepted_fd);
0262
0263
0264
0265 if (!ASSERT_OK(join_cgroup("/sock_policy_empty"), "join root cgroup"))
0266 goto detach_cgroup;
0267
0268 fd = socket(AF_INET6, SOCK_STREAM, 0);
0269 if (!ASSERT_GE(fd, 0, "socket(SOCK_STREAM)"))
0270 goto detach_cgroup;
0271
0272 prio = 0;
0273 socklen = sizeof(prio);
0274 ASSERT_GE(getsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio, &socklen), 0,
0275 "getsockopt");
0276 ASSERT_EQ(prio, 0, "sk_priority");
0277
0278 close(fd);
0279
0280 detach_cgroup:
0281 ASSERT_GE(bpf_prog_detach2(post_create_prog_fd2, cgroup_fd,
0282 BPF_LSM_CGROUP), 0, "detach_create");
0283 close(bind_link_fd);
0284
0285 ASSERT_GE(bpf_prog_detach2(alloc_prog_fd, cgroup_fd,
0286 BPF_LSM_CGROUP), 0, "detach_alloc");
0287 ASSERT_GE(bpf_prog_detach2(clone_prog_fd, cgroup_fd,
0288 BPF_LSM_CGROUP), 0, "detach_clone");
0289
0290 close_cgroup:
0291 close(cgroup_fd);
0292 close(cgroup_fd2);
0293 close(cgroup_fd3);
0294 lsm_cgroup__destroy(skel);
0295 }
0296
0297 static void test_lsm_cgroup_nonvoid(void)
0298 {
0299 struct lsm_cgroup_nonvoid *skel = NULL;
0300
0301 skel = lsm_cgroup_nonvoid__open_and_load();
0302 ASSERT_NULL(skel, "open succeeds");
0303 lsm_cgroup_nonvoid__destroy(skel);
0304 }
0305
0306 void test_lsm_cgroup(void)
0307 {
0308 if (test__start_subtest("functional"))
0309 test_lsm_cgroup_functional();
0310 if (test__start_subtest("nonvoid"))
0311 test_lsm_cgroup_nonvoid();
0312 btf__free(btf);
0313 }