1042 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Landlock tests - Abstract UNIX socket4 *5 * Copyright © 2024 Tahera Fahimi <fahimitahera@gmail.com>6 */7 8#define _GNU_SOURCE9#include <errno.h>10#include <fcntl.h>11#include <linux/landlock.h>12#include <sched.h>13#include <signal.h>14#include <stddef.h>15#include <sys/prctl.h>16#include <sys/socket.h>17#include <sys/stat.h>18#include <sys/types.h>19#include <sys/un.h>20#include <sys/wait.h>21#include <unistd.h>22 23#include "common.h"24#include "scoped_common.h"25 26/* Number of pending connections queue to be hold. */27const short backlog = 10;28 29static void create_fs_domain(struct __test_metadata *const _metadata)30{31 int ruleset_fd;32 struct landlock_ruleset_attr ruleset_attr = {33 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,34 };35 36 ruleset_fd =37 landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);38 EXPECT_LE(0, ruleset_fd)39 {40 TH_LOG("Failed to create a ruleset: %s", strerror(errno));41 }42 EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));43 EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));44 EXPECT_EQ(0, close(ruleset_fd));45}46 47FIXTURE(scoped_domains)48{49 struct service_fixture stream_address, dgram_address;50};51 52#include "scoped_base_variants.h"53 54FIXTURE_SETUP(scoped_domains)55{56 drop_caps(_metadata);57 58 memset(&self->stream_address, 0, sizeof(self->stream_address));59 memset(&self->dgram_address, 0, sizeof(self->dgram_address));60 set_unix_address(&self->stream_address, 0);61 set_unix_address(&self->dgram_address, 1);62}63 64FIXTURE_TEARDOWN(scoped_domains)65{66}67 68/*69 * Test unix_stream_connect() and unix_may_send() for a child connecting to its70 * parent, when they have scoped domain or no domain.71 */72TEST_F(scoped_domains, connect_to_parent)73{74 pid_t child;75 bool can_connect_to_parent;76 int status;77 int pipe_parent[2];78 int stream_server, dgram_server;79 80 /*81 * can_connect_to_parent is true if a child process can connect to its82 * parent process. This depends on the child process not being isolated83 * from the parent with a dedicated Landlock domain.84 */85 can_connect_to_parent = !variant->domain_child;86 87 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));88 if (variant->domain_both) {89 create_scoped_domain(_metadata,90 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);91 if (!__test_passed(_metadata))92 return;93 }94 95 child = fork();96 ASSERT_LE(0, child);97 if (child == 0) {98 int err;99 int stream_client, dgram_client;100 char buf_child;101 102 EXPECT_EQ(0, close(pipe_parent[1]));103 if (variant->domain_child)104 create_scoped_domain(105 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);106 107 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);108 ASSERT_LE(0, stream_client);109 dgram_client = socket(AF_UNIX, SOCK_DGRAM, 0);110 ASSERT_LE(0, dgram_client);111 112 /* Waits for the server. */113 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));114 115 err = connect(stream_client, &self->stream_address.unix_addr,116 self->stream_address.unix_addr_len);117 if (can_connect_to_parent) {118 EXPECT_EQ(0, err);119 } else {120 EXPECT_EQ(-1, err);121 EXPECT_EQ(EPERM, errno);122 }123 EXPECT_EQ(0, close(stream_client));124 125 err = connect(dgram_client, &self->dgram_address.unix_addr,126 self->dgram_address.unix_addr_len);127 if (can_connect_to_parent) {128 EXPECT_EQ(0, err);129 } else {130 EXPECT_EQ(-1, err);131 EXPECT_EQ(EPERM, errno);132 }133 EXPECT_EQ(0, close(dgram_client));134 _exit(_metadata->exit_code);135 return;136 }137 EXPECT_EQ(0, close(pipe_parent[0]));138 if (variant->domain_parent)139 create_scoped_domain(_metadata,140 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);141 142 stream_server = socket(AF_UNIX, SOCK_STREAM, 0);143 ASSERT_LE(0, stream_server);144 dgram_server = socket(AF_UNIX, SOCK_DGRAM, 0);145 ASSERT_LE(0, dgram_server);146 ASSERT_EQ(0, bind(stream_server, &self->stream_address.unix_addr,147 self->stream_address.unix_addr_len));148 ASSERT_EQ(0, bind(dgram_server, &self->dgram_address.unix_addr,149 self->dgram_address.unix_addr_len));150 ASSERT_EQ(0, listen(stream_server, backlog));151 152 /* Signals to child that the parent is listening. */153 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));154 155 ASSERT_EQ(child, waitpid(child, &status, 0));156 EXPECT_EQ(0, close(stream_server));157 EXPECT_EQ(0, close(dgram_server));158 159 if (WIFSIGNALED(status) || !WIFEXITED(status) ||160 WEXITSTATUS(status) != EXIT_SUCCESS)161 _metadata->exit_code = KSFT_FAIL;162}163 164/*165 * Test unix_stream_connect() and unix_may_send() for a parent connecting to166 * its child, when they have scoped domain or no domain.167 */168TEST_F(scoped_domains, connect_to_child)169{170 pid_t child;171 bool can_connect_to_child;172 int err_stream, err_dgram, errno_stream, errno_dgram, status;173 int pipe_child[2], pipe_parent[2];174 char buf;175 int stream_client, dgram_client;176 177 /*178 * can_connect_to_child is true if a parent process can connect to its179 * child process. The parent process is not isolated from the child180 * with a dedicated Landlock domain.181 */182 can_connect_to_child = !variant->domain_parent;183 184 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));185 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));186 if (variant->domain_both) {187 create_scoped_domain(_metadata,188 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);189 if (!__test_passed(_metadata))190 return;191 }192 193 child = fork();194 ASSERT_LE(0, child);195 if (child == 0) {196 int stream_server, dgram_server;197 198 EXPECT_EQ(0, close(pipe_parent[1]));199 EXPECT_EQ(0, close(pipe_child[0]));200 if (variant->domain_child)201 create_scoped_domain(202 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);203 204 /* Waits for the parent to be in a domain, if any. */205 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));206 207 stream_server = socket(AF_UNIX, SOCK_STREAM, 0);208 ASSERT_LE(0, stream_server);209 dgram_server = socket(AF_UNIX, SOCK_DGRAM, 0);210 ASSERT_LE(0, dgram_server);211 ASSERT_EQ(0,212 bind(stream_server, &self->stream_address.unix_addr,213 self->stream_address.unix_addr_len));214 ASSERT_EQ(0, bind(dgram_server, &self->dgram_address.unix_addr,215 self->dgram_address.unix_addr_len));216 ASSERT_EQ(0, listen(stream_server, backlog));217 218 /* Signals to the parent that child is listening. */219 ASSERT_EQ(1, write(pipe_child[1], ".", 1));220 221 /* Waits to connect. */222 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));223 EXPECT_EQ(0, close(stream_server));224 EXPECT_EQ(0, close(dgram_server));225 _exit(_metadata->exit_code);226 return;227 }228 EXPECT_EQ(0, close(pipe_child[1]));229 EXPECT_EQ(0, close(pipe_parent[0]));230 231 if (variant->domain_parent)232 create_scoped_domain(_metadata,233 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);234 235 /* Signals that the parent is in a domain, if any. */236 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));237 238 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);239 ASSERT_LE(0, stream_client);240 dgram_client = socket(AF_UNIX, SOCK_DGRAM, 0);241 ASSERT_LE(0, dgram_client);242 243 /* Waits for the child to listen */244 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));245 err_stream = connect(stream_client, &self->stream_address.unix_addr,246 self->stream_address.unix_addr_len);247 errno_stream = errno;248 err_dgram = connect(dgram_client, &self->dgram_address.unix_addr,249 self->dgram_address.unix_addr_len);250 errno_dgram = errno;251 if (can_connect_to_child) {252 EXPECT_EQ(0, err_stream);253 EXPECT_EQ(0, err_dgram);254 } else {255 EXPECT_EQ(-1, err_stream);256 EXPECT_EQ(-1, err_dgram);257 EXPECT_EQ(EPERM, errno_stream);258 EXPECT_EQ(EPERM, errno_dgram);259 }260 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));261 EXPECT_EQ(0, close(stream_client));262 EXPECT_EQ(0, close(dgram_client));263 264 ASSERT_EQ(child, waitpid(child, &status, 0));265 if (WIFSIGNALED(status) || !WIFEXITED(status) ||266 WEXITSTATUS(status) != EXIT_SUCCESS)267 _metadata->exit_code = KSFT_FAIL;268}269 270FIXTURE(scoped_vs_unscoped)271{272 struct service_fixture parent_stream_address, parent_dgram_address,273 child_stream_address, child_dgram_address;274};275 276#include "scoped_multiple_domain_variants.h"277 278FIXTURE_SETUP(scoped_vs_unscoped)279{280 drop_caps(_metadata);281 282 memset(&self->parent_stream_address, 0,283 sizeof(self->parent_stream_address));284 set_unix_address(&self->parent_stream_address, 0);285 memset(&self->parent_dgram_address, 0,286 sizeof(self->parent_dgram_address));287 set_unix_address(&self->parent_dgram_address, 1);288 memset(&self->child_stream_address, 0,289 sizeof(self->child_stream_address));290 set_unix_address(&self->child_stream_address, 2);291 memset(&self->child_dgram_address, 0,292 sizeof(self->child_dgram_address));293 set_unix_address(&self->child_dgram_address, 3);294}295 296FIXTURE_TEARDOWN(scoped_vs_unscoped)297{298}299 300/*301 * Test unix_stream_connect and unix_may_send for parent, child and302 * grand child processes when they can have scoped or non-scoped domains.303 */304TEST_F(scoped_vs_unscoped, unix_scoping)305{306 pid_t child;307 int status;308 bool can_connect_to_parent, can_connect_to_child;309 int pipe_parent[2];310 int stream_server_parent, dgram_server_parent;311 312 can_connect_to_child = (variant->domain_grand_child != SCOPE_SANDBOX);313 can_connect_to_parent = (can_connect_to_child &&314 (variant->domain_children != SCOPE_SANDBOX));315 316 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));317 318 if (variant->domain_all == OTHER_SANDBOX)319 create_fs_domain(_metadata);320 else if (variant->domain_all == SCOPE_SANDBOX)321 create_scoped_domain(_metadata,322 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);323 324 child = fork();325 ASSERT_LE(0, child);326 if (child == 0) {327 int stream_server_child, dgram_server_child;328 int pipe_child[2];329 pid_t grand_child;330 331 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));332 333 if (variant->domain_children == OTHER_SANDBOX)334 create_fs_domain(_metadata);335 else if (variant->domain_children == SCOPE_SANDBOX)336 create_scoped_domain(337 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);338 339 grand_child = fork();340 ASSERT_LE(0, grand_child);341 if (grand_child == 0) {342 char buf;343 int stream_err, dgram_err, stream_errno, dgram_errno;344 int stream_client, dgram_client;345 346 EXPECT_EQ(0, close(pipe_parent[1]));347 EXPECT_EQ(0, close(pipe_child[1]));348 349 if (variant->domain_grand_child == OTHER_SANDBOX)350 create_fs_domain(_metadata);351 else if (variant->domain_grand_child == SCOPE_SANDBOX)352 create_scoped_domain(353 _metadata,354 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);355 356 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);357 ASSERT_LE(0, stream_client);358 dgram_client = socket(AF_UNIX, SOCK_DGRAM, 0);359 ASSERT_LE(0, dgram_client);360 361 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));362 stream_err = connect(363 stream_client,364 &self->child_stream_address.unix_addr,365 self->child_stream_address.unix_addr_len);366 stream_errno = errno;367 dgram_err = connect(368 dgram_client,369 &self->child_dgram_address.unix_addr,370 self->child_dgram_address.unix_addr_len);371 dgram_errno = errno;372 if (can_connect_to_child) {373 EXPECT_EQ(0, stream_err);374 EXPECT_EQ(0, dgram_err);375 } else {376 EXPECT_EQ(-1, stream_err);377 EXPECT_EQ(-1, dgram_err);378 EXPECT_EQ(EPERM, stream_errno);379 EXPECT_EQ(EPERM, dgram_errno);380 }381 382 EXPECT_EQ(0, close(stream_client));383 stream_client = socket(AF_UNIX, SOCK_STREAM, 0);384 ASSERT_LE(0, stream_client);385 /* Datagram sockets can "reconnect". */386 387 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));388 stream_err = connect(389 stream_client,390 &self->parent_stream_address.unix_addr,391 self->parent_stream_address.unix_addr_len);392 stream_errno = errno;393 dgram_err = connect(394 dgram_client,395 &self->parent_dgram_address.unix_addr,396 self->parent_dgram_address.unix_addr_len);397 dgram_errno = errno;398 if (can_connect_to_parent) {399 EXPECT_EQ(0, stream_err);400 EXPECT_EQ(0, dgram_err);401 } else {402 EXPECT_EQ(-1, stream_err);403 EXPECT_EQ(-1, dgram_err);404 EXPECT_EQ(EPERM, stream_errno);405 EXPECT_EQ(EPERM, dgram_errno);406 }407 EXPECT_EQ(0, close(stream_client));408 EXPECT_EQ(0, close(dgram_client));409 410 _exit(_metadata->exit_code);411 return;412 }413 EXPECT_EQ(0, close(pipe_child[0]));414 if (variant->domain_child == OTHER_SANDBOX)415 create_fs_domain(_metadata);416 else if (variant->domain_child == SCOPE_SANDBOX)417 create_scoped_domain(418 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);419 420 stream_server_child = socket(AF_UNIX, SOCK_STREAM, 0);421 ASSERT_LE(0, stream_server_child);422 dgram_server_child = socket(AF_UNIX, SOCK_DGRAM, 0);423 ASSERT_LE(0, dgram_server_child);424 425 ASSERT_EQ(0, bind(stream_server_child,426 &self->child_stream_address.unix_addr,427 self->child_stream_address.unix_addr_len));428 ASSERT_EQ(0, bind(dgram_server_child,429 &self->child_dgram_address.unix_addr,430 self->child_dgram_address.unix_addr_len));431 ASSERT_EQ(0, listen(stream_server_child, backlog));432 433 ASSERT_EQ(1, write(pipe_child[1], ".", 1));434 ASSERT_EQ(grand_child, waitpid(grand_child, &status, 0));435 EXPECT_EQ(0, close(stream_server_child))436 EXPECT_EQ(0, close(dgram_server_child));437 return;438 }439 EXPECT_EQ(0, close(pipe_parent[0]));440 441 if (variant->domain_parent == OTHER_SANDBOX)442 create_fs_domain(_metadata);443 else if (variant->domain_parent == SCOPE_SANDBOX)444 create_scoped_domain(_metadata,445 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);446 447 stream_server_parent = socket(AF_UNIX, SOCK_STREAM, 0);448 ASSERT_LE(0, stream_server_parent);449 dgram_server_parent = socket(AF_UNIX, SOCK_DGRAM, 0);450 ASSERT_LE(0, dgram_server_parent);451 ASSERT_EQ(0, bind(stream_server_parent,452 &self->parent_stream_address.unix_addr,453 self->parent_stream_address.unix_addr_len));454 ASSERT_EQ(0, bind(dgram_server_parent,455 &self->parent_dgram_address.unix_addr,456 self->parent_dgram_address.unix_addr_len));457 458 ASSERT_EQ(0, listen(stream_server_parent, backlog));459 460 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));461 ASSERT_EQ(child, waitpid(child, &status, 0));462 EXPECT_EQ(0, close(stream_server_parent));463 EXPECT_EQ(0, close(dgram_server_parent));464 465 if (WIFSIGNALED(status) || !WIFEXITED(status) ||466 WEXITSTATUS(status) != EXIT_SUCCESS)467 _metadata->exit_code = KSFT_FAIL;468}469 470FIXTURE(outside_socket)471{472 struct service_fixture address, transit_address;473};474 475FIXTURE_VARIANT(outside_socket)476{477 const bool child_socket;478 const int type;479};480 481/* clang-format off */482FIXTURE_VARIANT_ADD(outside_socket, allow_dgram_child) {483 /* clang-format on */484 .child_socket = true,485 .type = SOCK_DGRAM,486};487 488/* clang-format off */489FIXTURE_VARIANT_ADD(outside_socket, deny_dgram_server) {490 /* clang-format on */491 .child_socket = false,492 .type = SOCK_DGRAM,493};494 495/* clang-format off */496FIXTURE_VARIANT_ADD(outside_socket, allow_stream_child) {497 /* clang-format on */498 .child_socket = true,499 .type = SOCK_STREAM,500};501 502/* clang-format off */503FIXTURE_VARIANT_ADD(outside_socket, deny_stream_server) {504 /* clang-format on */505 .child_socket = false,506 .type = SOCK_STREAM,507};508 509FIXTURE_SETUP(outside_socket)510{511 drop_caps(_metadata);512 513 memset(&self->transit_address, 0, sizeof(self->transit_address));514 set_unix_address(&self->transit_address, 0);515 memset(&self->address, 0, sizeof(self->address));516 set_unix_address(&self->address, 1);517}518 519FIXTURE_TEARDOWN(outside_socket)520{521}522 523/*524 * Test unix_stream_connect and unix_may_send for parent and child processes525 * when connecting socket has different domain than the process using it.526 */527TEST_F(outside_socket, socket_with_different_domain)528{529 pid_t child;530 int err, status;531 int pipe_child[2], pipe_parent[2];532 char buf_parent;533 int server_socket;534 535 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));536 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));537 538 child = fork();539 ASSERT_LE(0, child);540 if (child == 0) {541 int client_socket;542 char buf_child;543 544 EXPECT_EQ(0, close(pipe_parent[1]));545 EXPECT_EQ(0, close(pipe_child[0]));546 547 /* Client always has a domain. */548 create_scoped_domain(_metadata,549 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);550 551 if (variant->child_socket) {552 int data_socket, passed_socket, stream_server;553 554 passed_socket = socket(AF_UNIX, variant->type, 0);555 ASSERT_LE(0, passed_socket);556 stream_server = socket(AF_UNIX, SOCK_STREAM, 0);557 ASSERT_LE(0, stream_server);558 ASSERT_EQ(0, bind(stream_server,559 &self->transit_address.unix_addr,560 self->transit_address.unix_addr_len));561 ASSERT_EQ(0, listen(stream_server, backlog));562 ASSERT_EQ(1, write(pipe_child[1], ".", 1));563 data_socket = accept(stream_server, NULL, NULL);564 ASSERT_LE(0, data_socket);565 ASSERT_EQ(0, send_fd(data_socket, passed_socket));566 EXPECT_EQ(0, close(passed_socket));567 EXPECT_EQ(0, close(stream_server));568 }569 570 client_socket = socket(AF_UNIX, variant->type, 0);571 ASSERT_LE(0, client_socket);572 573 /* Waits for parent signal for connection. */574 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));575 err = connect(client_socket, &self->address.unix_addr,576 self->address.unix_addr_len);577 if (variant->child_socket) {578 EXPECT_EQ(0, err);579 } else {580 EXPECT_EQ(-1, err);581 EXPECT_EQ(EPERM, errno);582 }583 EXPECT_EQ(0, close(client_socket));584 _exit(_metadata->exit_code);585 return;586 }587 EXPECT_EQ(0, close(pipe_child[1]));588 EXPECT_EQ(0, close(pipe_parent[0]));589 590 if (variant->child_socket) {591 int client_child = socket(AF_UNIX, SOCK_STREAM, 0);592 593 ASSERT_LE(0, client_child);594 ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1));595 ASSERT_EQ(0, connect(client_child,596 &self->transit_address.unix_addr,597 self->transit_address.unix_addr_len));598 server_socket = recv_fd(client_child);599 EXPECT_EQ(0, close(client_child));600 } else {601 server_socket = socket(AF_UNIX, variant->type, 0);602 }603 ASSERT_LE(0, server_socket);604 605 /* Server always has a domain. */606 create_scoped_domain(_metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);607 608 ASSERT_EQ(0, bind(server_socket, &self->address.unix_addr,609 self->address.unix_addr_len));610 if (variant->type == SOCK_STREAM)611 ASSERT_EQ(0, listen(server_socket, backlog));612 613 /* Signals to child that the parent is listening. */614 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));615 616 ASSERT_EQ(child, waitpid(child, &status, 0));617 EXPECT_EQ(0, close(server_socket));618 619 if (WIFSIGNALED(status) || !WIFEXITED(status) ||620 WEXITSTATUS(status) != EXIT_SUCCESS)621 _metadata->exit_code = KSFT_FAIL;622}623 624static const char stream_path[] = TMP_DIR "/stream.sock";625static const char dgram_path[] = TMP_DIR "/dgram.sock";626 627/* clang-format off */628FIXTURE(various_address_sockets) {};629/* clang-format on */630 631FIXTURE_VARIANT(various_address_sockets)632{633 const int domain;634};635 636/* clang-format off */637FIXTURE_VARIANT_ADD(various_address_sockets, pathname_socket_scoped_domain) {638 /* clang-format on */639 .domain = SCOPE_SANDBOX,640};641 642/* clang-format off */643FIXTURE_VARIANT_ADD(various_address_sockets, pathname_socket_other_domain) {644 /* clang-format on */645 .domain = OTHER_SANDBOX,646};647 648/* clang-format off */649FIXTURE_VARIANT_ADD(various_address_sockets, pathname_socket_no_domain) {650 /* clang-format on */651 .domain = NO_SANDBOX,652};653 654FIXTURE_SETUP(various_address_sockets)655{656 drop_caps(_metadata);657 658 umask(0077);659 ASSERT_EQ(0, mkdir(TMP_DIR, 0700));660}661 662FIXTURE_TEARDOWN(various_address_sockets)663{664 EXPECT_EQ(0, unlink(stream_path));665 EXPECT_EQ(0, unlink(dgram_path));666 EXPECT_EQ(0, rmdir(TMP_DIR));667}668 669TEST_F(various_address_sockets, scoped_pathname_sockets)670{671 socklen_t size_stream, size_dgram;672 pid_t child;673 int status;674 char buf_child, buf_parent;675 int pipe_parent[2];676 int unnamed_sockets[2];677 int stream_pathname_socket, dgram_pathname_socket,678 stream_abstract_socket, dgram_abstract_socket, data_socket;679 struct service_fixture stream_abstract_addr, dgram_abstract_addr;680 struct sockaddr_un stream_pathname_addr = {681 .sun_family = AF_UNIX,682 };683 struct sockaddr_un dgram_pathname_addr = {684 .sun_family = AF_UNIX,685 };686 687 /* Pathname address. */688 snprintf(stream_pathname_addr.sun_path,689 sizeof(stream_pathname_addr.sun_path), "%s", stream_path);690 size_stream = offsetof(struct sockaddr_un, sun_path) +691 strlen(stream_pathname_addr.sun_path);692 snprintf(dgram_pathname_addr.sun_path,693 sizeof(dgram_pathname_addr.sun_path), "%s", dgram_path);694 size_dgram = offsetof(struct sockaddr_un, sun_path) +695 strlen(dgram_pathname_addr.sun_path);696 697 /* Abstract address. */698 memset(&stream_abstract_addr, 0, sizeof(stream_abstract_addr));699 set_unix_address(&stream_abstract_addr, 0);700 memset(&dgram_abstract_addr, 0, sizeof(dgram_abstract_addr));701 set_unix_address(&dgram_abstract_addr, 1);702 703 /* Unnamed address for datagram socket. */704 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_DGRAM, 0, unnamed_sockets));705 706 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));707 708 child = fork();709 ASSERT_LE(0, child);710 if (child == 0) {711 int err;712 713 EXPECT_EQ(0, close(pipe_parent[1]));714 EXPECT_EQ(0, close(unnamed_sockets[1]));715 716 if (variant->domain == SCOPE_SANDBOX)717 create_scoped_domain(718 _metadata, LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);719 else if (variant->domain == OTHER_SANDBOX)720 create_fs_domain(_metadata);721 722 /* Waits for parent to listen. */723 ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));724 EXPECT_EQ(0, close(pipe_parent[0]));725 726 /* Checks that we can send data through a datagram socket. */727 ASSERT_EQ(1, write(unnamed_sockets[0], "a", 1));728 EXPECT_EQ(0, close(unnamed_sockets[0]));729 730 /* Connects with pathname sockets. */731 stream_pathname_socket = socket(AF_UNIX, SOCK_STREAM, 0);732 ASSERT_LE(0, stream_pathname_socket);733 ASSERT_EQ(0, connect(stream_pathname_socket,734 &stream_pathname_addr, size_stream));735 ASSERT_EQ(1, write(stream_pathname_socket, "b", 1));736 EXPECT_EQ(0, close(stream_pathname_socket));737 738 /* Sends without connection. */739 dgram_pathname_socket = socket(AF_UNIX, SOCK_DGRAM, 0);740 ASSERT_LE(0, dgram_pathname_socket);741 err = sendto(dgram_pathname_socket, "c", 1, 0,742 &dgram_pathname_addr, size_dgram);743 EXPECT_EQ(1, err);744 745 /* Sends with connection. */746 ASSERT_EQ(0, connect(dgram_pathname_socket,747 &dgram_pathname_addr, size_dgram));748 ASSERT_EQ(1, write(dgram_pathname_socket, "d", 1));749 EXPECT_EQ(0, close(dgram_pathname_socket));750 751 /* Connects with abstract sockets. */752 stream_abstract_socket = socket(AF_UNIX, SOCK_STREAM, 0);753 ASSERT_LE(0, stream_abstract_socket);754 err = connect(stream_abstract_socket,755 &stream_abstract_addr.unix_addr,756 stream_abstract_addr.unix_addr_len);757 if (variant->domain == SCOPE_SANDBOX) {758 EXPECT_EQ(-1, err);759 EXPECT_EQ(EPERM, errno);760 } else {761 EXPECT_EQ(0, err);762 ASSERT_EQ(1, write(stream_abstract_socket, "e", 1));763 }764 EXPECT_EQ(0, close(stream_abstract_socket));765 766 /* Sends without connection. */767 dgram_abstract_socket = socket(AF_UNIX, SOCK_DGRAM, 0);768 ASSERT_LE(0, dgram_abstract_socket);769 err = sendto(dgram_abstract_socket, "f", 1, 0,770 &dgram_abstract_addr.unix_addr,771 dgram_abstract_addr.unix_addr_len);772 if (variant->domain == SCOPE_SANDBOX) {773 EXPECT_EQ(-1, err);774 EXPECT_EQ(EPERM, errno);775 } else {776 EXPECT_EQ(1, err);777 }778 779 /* Sends with connection. */780 err = connect(dgram_abstract_socket,781 &dgram_abstract_addr.unix_addr,782 dgram_abstract_addr.unix_addr_len);783 if (variant->domain == SCOPE_SANDBOX) {784 EXPECT_EQ(-1, err);785 EXPECT_EQ(EPERM, errno);786 } else {787 EXPECT_EQ(0, err);788 ASSERT_EQ(1, write(dgram_abstract_socket, "g", 1));789 }790 EXPECT_EQ(0, close(dgram_abstract_socket));791 792 _exit(_metadata->exit_code);793 return;794 }795 EXPECT_EQ(0, close(pipe_parent[0]));796 EXPECT_EQ(0, close(unnamed_sockets[0]));797 798 /* Sets up pathname servers. */799 stream_pathname_socket = socket(AF_UNIX, SOCK_STREAM, 0);800 ASSERT_LE(0, stream_pathname_socket);801 ASSERT_EQ(0, bind(stream_pathname_socket, &stream_pathname_addr,802 size_stream));803 ASSERT_EQ(0, listen(stream_pathname_socket, backlog));804 805 dgram_pathname_socket = socket(AF_UNIX, SOCK_DGRAM, 0);806 ASSERT_LE(0, dgram_pathname_socket);807 ASSERT_EQ(0, bind(dgram_pathname_socket, &dgram_pathname_addr,808 size_dgram));809 810 /* Sets up abstract servers. */811 stream_abstract_socket = socket(AF_UNIX, SOCK_STREAM, 0);812 ASSERT_LE(0, stream_abstract_socket);813 ASSERT_EQ(0,814 bind(stream_abstract_socket, &stream_abstract_addr.unix_addr,815 stream_abstract_addr.unix_addr_len));816 817 dgram_abstract_socket = socket(AF_UNIX, SOCK_DGRAM, 0);818 ASSERT_LE(0, dgram_abstract_socket);819 ASSERT_EQ(0, bind(dgram_abstract_socket, &dgram_abstract_addr.unix_addr,820 dgram_abstract_addr.unix_addr_len));821 ASSERT_EQ(0, listen(stream_abstract_socket, backlog));822 823 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));824 EXPECT_EQ(0, close(pipe_parent[1]));825 826 /* Reads from unnamed socket. */827 ASSERT_EQ(1, read(unnamed_sockets[1], &buf_parent, sizeof(buf_parent)));828 ASSERT_EQ('a', buf_parent);829 EXPECT_LE(0, close(unnamed_sockets[1]));830 831 /* Reads from pathname sockets. */832 data_socket = accept(stream_pathname_socket, NULL, NULL);833 ASSERT_LE(0, data_socket);834 ASSERT_EQ(1, read(data_socket, &buf_parent, sizeof(buf_parent)));835 ASSERT_EQ('b', buf_parent);836 EXPECT_EQ(0, close(data_socket));837 EXPECT_EQ(0, close(stream_pathname_socket));838 839 ASSERT_EQ(1,840 read(dgram_pathname_socket, &buf_parent, sizeof(buf_parent)));841 ASSERT_EQ('c', buf_parent);842 ASSERT_EQ(1,843 read(dgram_pathname_socket, &buf_parent, sizeof(buf_parent)));844 ASSERT_EQ('d', buf_parent);845 EXPECT_EQ(0, close(dgram_pathname_socket));846 847 if (variant->domain != SCOPE_SANDBOX) {848 /* Reads from abstract sockets if allowed to send. */849 data_socket = accept(stream_abstract_socket, NULL, NULL);850 ASSERT_LE(0, data_socket);851 ASSERT_EQ(1,852 read(data_socket, &buf_parent, sizeof(buf_parent)));853 ASSERT_EQ('e', buf_parent);854 EXPECT_EQ(0, close(data_socket));855 856 ASSERT_EQ(1, read(dgram_abstract_socket, &buf_parent,857 sizeof(buf_parent)));858 ASSERT_EQ('f', buf_parent);859 ASSERT_EQ(1, read(dgram_abstract_socket, &buf_parent,860 sizeof(buf_parent)));861 ASSERT_EQ('g', buf_parent);862 }863 864 /* Waits for all abstract socket tests. */865 ASSERT_EQ(child, waitpid(child, &status, 0));866 EXPECT_EQ(0, close(stream_abstract_socket));867 EXPECT_EQ(0, close(dgram_abstract_socket));868 869 if (WIFSIGNALED(status) || !WIFEXITED(status) ||870 WEXITSTATUS(status) != EXIT_SUCCESS)871 _metadata->exit_code = KSFT_FAIL;872}873 874TEST(datagram_sockets)875{876 struct service_fixture connected_addr, non_connected_addr;877 int server_conn_socket, server_unconn_socket;878 int pipe_parent[2], pipe_child[2];879 int status;880 char buf;881 pid_t child;882 883 drop_caps(_metadata);884 memset(&connected_addr, 0, sizeof(connected_addr));885 set_unix_address(&connected_addr, 0);886 memset(&non_connected_addr, 0, sizeof(non_connected_addr));887 set_unix_address(&non_connected_addr, 1);888 889 ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));890 ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));891 892 child = fork();893 ASSERT_LE(0, child);894 if (child == 0) {895 int client_conn_socket, client_unconn_socket;896 897 EXPECT_EQ(0, close(pipe_parent[1]));898 EXPECT_EQ(0, close(pipe_child[0]));899 900 client_conn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);901 client_unconn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);902 ASSERT_LE(0, client_conn_socket);903 ASSERT_LE(0, client_unconn_socket);904 905 /* Waits for parent to listen. */906 ASSERT_EQ(1, read(pipe_parent[0], &buf, 1));907 ASSERT_EQ(0,908 connect(client_conn_socket, &connected_addr.unix_addr,909 connected_addr.unix_addr_len));910 911 /*912 * Both connected and non-connected sockets can send data when913 * the domain is not scoped.914 */915 ASSERT_EQ(1, send(client_conn_socket, ".", 1, 0));916 ASSERT_EQ(1, sendto(client_unconn_socket, ".", 1, 0,917 &non_connected_addr.unix_addr,918 non_connected_addr.unix_addr_len));919 ASSERT_EQ(1, write(pipe_child[1], ".", 1));920 921 /* Scopes the domain. */922 create_scoped_domain(_metadata,923 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);924 925 /*926 * Connected socket sends data to the receiver, but the927 * non-connected socket must fail to send data.928 */929 ASSERT_EQ(1, send(client_conn_socket, ".", 1, 0));930 ASSERT_EQ(-1, sendto(client_unconn_socket, ".", 1, 0,931 &non_connected_addr.unix_addr,932 non_connected_addr.unix_addr_len));933 ASSERT_EQ(EPERM, errno);934 ASSERT_EQ(1, write(pipe_child[1], ".", 1));935 936 EXPECT_EQ(0, close(client_conn_socket));937 EXPECT_EQ(0, close(client_unconn_socket));938 _exit(_metadata->exit_code);939 return;940 }941 EXPECT_EQ(0, close(pipe_parent[0]));942 EXPECT_EQ(0, close(pipe_child[1]));943 944 server_conn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);945 server_unconn_socket = socket(AF_UNIX, SOCK_DGRAM, 0);946 ASSERT_LE(0, server_conn_socket);947 ASSERT_LE(0, server_unconn_socket);948 949 ASSERT_EQ(0, bind(server_conn_socket, &connected_addr.unix_addr,950 connected_addr.unix_addr_len));951 ASSERT_EQ(0, bind(server_unconn_socket, &non_connected_addr.unix_addr,952 non_connected_addr.unix_addr_len));953 ASSERT_EQ(1, write(pipe_parent[1], ".", 1));954 955 /* Waits for child to test. */956 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));957 ASSERT_EQ(1, recv(server_conn_socket, &buf, 1, 0));958 ASSERT_EQ(1, recv(server_unconn_socket, &buf, 1, 0));959 960 /*961 * Connected datagram socket will receive data, but962 * non-connected datagram socket does not receive data.963 */964 ASSERT_EQ(1, read(pipe_child[0], &buf, 1));965 ASSERT_EQ(1, recv(server_conn_socket, &buf, 1, 0));966 967 /* Waits for all tests to finish. */968 ASSERT_EQ(child, waitpid(child, &status, 0));969 EXPECT_EQ(0, close(server_conn_socket));970 EXPECT_EQ(0, close(server_unconn_socket));971 972 if (WIFSIGNALED(status) || !WIFEXITED(status) ||973 WEXITSTATUS(status) != EXIT_SUCCESS)974 _metadata->exit_code = KSFT_FAIL;975}976 977TEST(self_connect)978{979 struct service_fixture connected_addr, non_connected_addr;980 int connected_socket, non_connected_socket, status;981 pid_t child;982 983 drop_caps(_metadata);984 memset(&connected_addr, 0, sizeof(connected_addr));985 set_unix_address(&connected_addr, 0);986 memset(&non_connected_addr, 0, sizeof(non_connected_addr));987 set_unix_address(&non_connected_addr, 1);988 989 connected_socket = socket(AF_UNIX, SOCK_DGRAM, 0);990 non_connected_socket = socket(AF_UNIX, SOCK_DGRAM, 0);991 ASSERT_LE(0, connected_socket);992 ASSERT_LE(0, non_connected_socket);993 994 ASSERT_EQ(0, bind(connected_socket, &connected_addr.unix_addr,995 connected_addr.unix_addr_len));996 ASSERT_EQ(0, bind(non_connected_socket, &non_connected_addr.unix_addr,997 non_connected_addr.unix_addr_len));998 999 child = fork();1000 ASSERT_LE(0, child);1001 if (child == 0) {1002 /* Child's domain is scoped. */1003 create_scoped_domain(_metadata,1004 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET);1005 1006 /*1007 * The child inherits the sockets, and cannot connect or1008 * send data to them.1009 */1010 ASSERT_EQ(-1,1011 connect(connected_socket, &connected_addr.unix_addr,1012 connected_addr.unix_addr_len));1013 ASSERT_EQ(EPERM, errno);1014 1015 ASSERT_EQ(-1, sendto(connected_socket, ".", 1, 0,1016 &connected_addr.unix_addr,1017 connected_addr.unix_addr_len));1018 ASSERT_EQ(EPERM, errno);1019 1020 ASSERT_EQ(-1, sendto(non_connected_socket, ".", 1, 0,1021 &non_connected_addr.unix_addr,1022 non_connected_addr.unix_addr_len));1023 ASSERT_EQ(EPERM, errno);1024 1025 EXPECT_EQ(0, close(connected_socket));1026 EXPECT_EQ(0, close(non_connected_socket));1027 _exit(_metadata->exit_code);1028 return;1029 }1030 1031 /* Waits for all tests to finish. */1032 ASSERT_EQ(child, waitpid(child, &status, 0));1033 EXPECT_EQ(0, close(connected_socket));1034 EXPECT_EQ(0, close(non_connected_socket));1035 1036 if (WIFSIGNALED(status) || !WIFEXITED(status) ||1037 WEXITSTATUS(status) != EXIT_SUCCESS)1038 _metadata->exit_code = KSFT_FAIL;1039}1040 1041TEST_HARNESS_MAIN1042