cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

base_test.c (10746B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Landlock tests - Common user space base
      4 *
      5 * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
      6 * Copyright © 2019-2020 ANSSI
      7 */
      8
      9#define _GNU_SOURCE
     10#include <errno.h>
     11#include <fcntl.h>
     12#include <linux/landlock.h>
     13#include <string.h>
     14#include <sys/prctl.h>
     15#include <sys/socket.h>
     16#include <sys/types.h>
     17
     18#include "common.h"
     19
     20#ifndef O_PATH
     21#define O_PATH 010000000
     22#endif
     23
     24TEST(inconsistent_attr)
     25{
     26	const long page_size = sysconf(_SC_PAGESIZE);
     27	char *const buf = malloc(page_size + 1);
     28	struct landlock_ruleset_attr *const ruleset_attr = (void *)buf;
     29
     30	ASSERT_NE(NULL, buf);
     31
     32	/* Checks copy_from_user(). */
     33	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 0, 0));
     34	/* The size if less than sizeof(struct landlock_attr_enforce). */
     35	ASSERT_EQ(EINVAL, errno);
     36	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 1, 0));
     37	ASSERT_EQ(EINVAL, errno);
     38	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 7, 0));
     39	ASSERT_EQ(EINVAL, errno);
     40
     41	ASSERT_EQ(-1, landlock_create_ruleset(NULL, 1, 0));
     42	/* The size if less than sizeof(struct landlock_attr_enforce). */
     43	ASSERT_EQ(EFAULT, errno);
     44
     45	ASSERT_EQ(-1, landlock_create_ruleset(
     46			      NULL, sizeof(struct landlock_ruleset_attr), 0));
     47	ASSERT_EQ(EFAULT, errno);
     48
     49	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
     50	ASSERT_EQ(E2BIG, errno);
     51
     52	/* Checks minimal valid attribute size. */
     53	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 8, 0));
     54	ASSERT_EQ(ENOMSG, errno);
     55	ASSERT_EQ(-1, landlock_create_ruleset(
     56			      ruleset_attr,
     57			      sizeof(struct landlock_ruleset_attr), 0));
     58	ASSERT_EQ(ENOMSG, errno);
     59	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
     60	ASSERT_EQ(ENOMSG, errno);
     61
     62	/* Checks non-zero value. */
     63	buf[page_size - 2] = '.';
     64	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0));
     65	ASSERT_EQ(E2BIG, errno);
     66
     67	ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0));
     68	ASSERT_EQ(E2BIG, errno);
     69
     70	free(buf);
     71}
     72
     73TEST(abi_version)
     74{
     75	const struct landlock_ruleset_attr ruleset_attr = {
     76		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
     77	};
     78	ASSERT_EQ(2, landlock_create_ruleset(NULL, 0,
     79					     LANDLOCK_CREATE_RULESET_VERSION));
     80
     81	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
     82					      LANDLOCK_CREATE_RULESET_VERSION));
     83	ASSERT_EQ(EINVAL, errno);
     84
     85	ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
     86					      LANDLOCK_CREATE_RULESET_VERSION));
     87	ASSERT_EQ(EINVAL, errno);
     88
     89	ASSERT_EQ(-1,
     90		  landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
     91					  LANDLOCK_CREATE_RULESET_VERSION));
     92	ASSERT_EQ(EINVAL, errno);
     93
     94	ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
     95					      LANDLOCK_CREATE_RULESET_VERSION |
     96						      1 << 31));
     97	ASSERT_EQ(EINVAL, errno);
     98}
     99
    100/* Tests ordering of syscall argument checks. */
    101TEST(create_ruleset_checks_ordering)
    102{
    103	const int last_flag = LANDLOCK_CREATE_RULESET_VERSION;
    104	const int invalid_flag = last_flag << 1;
    105	int ruleset_fd;
    106	const struct landlock_ruleset_attr ruleset_attr = {
    107		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
    108	};
    109
    110	/* Checks priority for invalid flags. */
    111	ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, invalid_flag));
    112	ASSERT_EQ(EINVAL, errno);
    113
    114	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, invalid_flag));
    115	ASSERT_EQ(EINVAL, errno);
    116
    117	ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
    118					      invalid_flag));
    119	ASSERT_EQ(EINVAL, errno);
    120
    121	ASSERT_EQ(-1,
    122		  landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
    123					  invalid_flag));
    124	ASSERT_EQ(EINVAL, errno);
    125
    126	/* Checks too big ruleset_attr size. */
    127	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, -1, 0));
    128	ASSERT_EQ(E2BIG, errno);
    129
    130	/* Checks too small ruleset_attr size. */
    131	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 0));
    132	ASSERT_EQ(EINVAL, errno);
    133	ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 1, 0));
    134	ASSERT_EQ(EINVAL, errno);
    135
    136	/* Checks valid call. */
    137	ruleset_fd =
    138		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
    139	ASSERT_LE(0, ruleset_fd);
    140	ASSERT_EQ(0, close(ruleset_fd));
    141}
    142
    143/* Tests ordering of syscall argument checks. */
    144TEST(add_rule_checks_ordering)
    145{
    146	const struct landlock_ruleset_attr ruleset_attr = {
    147		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
    148	};
    149	struct landlock_path_beneath_attr path_beneath_attr = {
    150		.allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
    151		.parent_fd = -1,
    152	};
    153	const int ruleset_fd =
    154		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
    155
    156	ASSERT_LE(0, ruleset_fd);
    157
    158	/* Checks invalid flags. */
    159	ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1));
    160	ASSERT_EQ(EINVAL, errno);
    161
    162	/* Checks invalid ruleset FD. */
    163	ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 0));
    164	ASSERT_EQ(EBADF, errno);
    165
    166	/* Checks invalid rule type. */
    167	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, 0, NULL, 0));
    168	ASSERT_EQ(EINVAL, errno);
    169
    170	/* Checks invalid rule attr. */
    171	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
    172					NULL, 0));
    173	ASSERT_EQ(EFAULT, errno);
    174
    175	/* Checks invalid path_beneath.parent_fd. */
    176	ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
    177					&path_beneath_attr, 0));
    178	ASSERT_EQ(EBADF, errno);
    179
    180	/* Checks valid call. */
    181	path_beneath_attr.parent_fd =
    182		open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
    183	ASSERT_LE(0, path_beneath_attr.parent_fd);
    184	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
    185				       &path_beneath_attr, 0));
    186	ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
    187	ASSERT_EQ(0, close(ruleset_fd));
    188}
    189
    190/* Tests ordering of syscall argument and permission checks. */
    191TEST(restrict_self_checks_ordering)
    192{
    193	const struct landlock_ruleset_attr ruleset_attr = {
    194		.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
    195	};
    196	struct landlock_path_beneath_attr path_beneath_attr = {
    197		.allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
    198		.parent_fd = -1,
    199	};
    200	const int ruleset_fd =
    201		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
    202
    203	ASSERT_LE(0, ruleset_fd);
    204	path_beneath_attr.parent_fd =
    205		open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
    206	ASSERT_LE(0, path_beneath_attr.parent_fd);
    207	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
    208				       &path_beneath_attr, 0));
    209	ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
    210
    211	/* Checks unprivileged enforcement without no_new_privs. */
    212	drop_caps(_metadata);
    213	ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
    214	ASSERT_EQ(EPERM, errno);
    215	ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
    216	ASSERT_EQ(EPERM, errno);
    217	ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
    218	ASSERT_EQ(EPERM, errno);
    219
    220	ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
    221
    222	/* Checks invalid flags. */
    223	ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
    224	ASSERT_EQ(EINVAL, errno);
    225
    226	/* Checks invalid ruleset FD. */
    227	ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
    228	ASSERT_EQ(EBADF, errno);
    229
    230	/* Checks valid call. */
    231	ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
    232	ASSERT_EQ(0, close(ruleset_fd));
    233}
    234
    235TEST(ruleset_fd_io)
    236{
    237	struct landlock_ruleset_attr ruleset_attr = {
    238		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
    239	};
    240	int ruleset_fd;
    241	char buf;
    242
    243	drop_caps(_metadata);
    244	ruleset_fd =
    245		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
    246	ASSERT_LE(0, ruleset_fd);
    247
    248	ASSERT_EQ(-1, write(ruleset_fd, ".", 1));
    249	ASSERT_EQ(EINVAL, errno);
    250	ASSERT_EQ(-1, read(ruleset_fd, &buf, 1));
    251	ASSERT_EQ(EINVAL, errno);
    252
    253	ASSERT_EQ(0, close(ruleset_fd));
    254}
    255
    256/* Tests enforcement of a ruleset FD transferred through a UNIX socket. */
    257TEST(ruleset_fd_transfer)
    258{
    259	struct landlock_ruleset_attr ruleset_attr = {
    260		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR,
    261	};
    262	struct landlock_path_beneath_attr path_beneath_attr = {
    263		.allowed_access = LANDLOCK_ACCESS_FS_READ_DIR,
    264	};
    265	int ruleset_fd_tx, dir_fd;
    266	union {
    267		/* Aligned ancillary data buffer. */
    268		char buf[CMSG_SPACE(sizeof(ruleset_fd_tx))];
    269		struct cmsghdr _align;
    270	} cmsg_tx = {};
    271	char data_tx = '.';
    272	struct iovec io = {
    273		.iov_base = &data_tx,
    274		.iov_len = sizeof(data_tx),
    275	};
    276	struct msghdr msg = {
    277		.msg_iov = &io,
    278		.msg_iovlen = 1,
    279		.msg_control = &cmsg_tx.buf,
    280		.msg_controllen = sizeof(cmsg_tx.buf),
    281	};
    282	struct cmsghdr *cmsg;
    283	int socket_fds[2];
    284	pid_t child;
    285	int status;
    286
    287	drop_caps(_metadata);
    288
    289	/* Creates a test ruleset with a simple rule. */
    290	ruleset_fd_tx =
    291		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
    292	ASSERT_LE(0, ruleset_fd_tx);
    293	path_beneath_attr.parent_fd =
    294		open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
    295	ASSERT_LE(0, path_beneath_attr.parent_fd);
    296	ASSERT_EQ(0,
    297		  landlock_add_rule(ruleset_fd_tx, LANDLOCK_RULE_PATH_BENEATH,
    298				    &path_beneath_attr, 0));
    299	ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
    300
    301	cmsg = CMSG_FIRSTHDR(&msg);
    302	ASSERT_NE(NULL, cmsg);
    303	cmsg->cmsg_len = CMSG_LEN(sizeof(ruleset_fd_tx));
    304	cmsg->cmsg_level = SOL_SOCKET;
    305	cmsg->cmsg_type = SCM_RIGHTS;
    306	memcpy(CMSG_DATA(cmsg), &ruleset_fd_tx, sizeof(ruleset_fd_tx));
    307
    308	/* Sends the ruleset FD over a socketpair and then close it. */
    309	ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
    310				socket_fds));
    311	ASSERT_EQ(sizeof(data_tx), sendmsg(socket_fds[0], &msg, 0));
    312	ASSERT_EQ(0, close(socket_fds[0]));
    313	ASSERT_EQ(0, close(ruleset_fd_tx));
    314
    315	child = fork();
    316	ASSERT_LE(0, child);
    317	if (child == 0) {
    318		int ruleset_fd_rx;
    319
    320		*(char *)msg.msg_iov->iov_base = '\0';
    321		ASSERT_EQ(sizeof(data_tx),
    322			  recvmsg(socket_fds[1], &msg, MSG_CMSG_CLOEXEC));
    323		ASSERT_EQ('.', *(char *)msg.msg_iov->iov_base);
    324		ASSERT_EQ(0, close(socket_fds[1]));
    325		cmsg = CMSG_FIRSTHDR(&msg);
    326		ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(ruleset_fd_tx)));
    327		memcpy(&ruleset_fd_rx, CMSG_DATA(cmsg), sizeof(ruleset_fd_tx));
    328
    329		/* Enforces the received ruleset on the child. */
    330		ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
    331		ASSERT_EQ(0, landlock_restrict_self(ruleset_fd_rx, 0));
    332		ASSERT_EQ(0, close(ruleset_fd_rx));
    333
    334		/* Checks that the ruleset enforcement. */
    335		ASSERT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
    336		ASSERT_EQ(EACCES, errno);
    337		dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
    338		ASSERT_LE(0, dir_fd);
    339		ASSERT_EQ(0, close(dir_fd));
    340		_exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE);
    341		return;
    342	}
    343
    344	ASSERT_EQ(0, close(socket_fds[1]));
    345
    346	/* Checks that the parent is unrestricted. */
    347	dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
    348	ASSERT_LE(0, dir_fd);
    349	ASSERT_EQ(0, close(dir_fd));
    350	dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
    351	ASSERT_LE(0, dir_fd);
    352	ASSERT_EQ(0, close(dir_fd));
    353
    354	ASSERT_EQ(child, waitpid(child, &status, 0));
    355	ASSERT_EQ(1, WIFEXITED(status));
    356	ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
    357}
    358
    359TEST_HARNESS_MAIN