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

close_range_test.c (13033B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#define _GNU_SOURCE
      4#include <errno.h>
      5#include <fcntl.h>
      6#include <linux/kernel.h>
      7#include <limits.h>
      8#include <stdbool.h>
      9#include <stdio.h>
     10#include <stdlib.h>
     11#include <string.h>
     12#include <syscall.h>
     13#include <unistd.h>
     14#include <sys/resource.h>
     15
     16#include "../kselftest_harness.h"
     17#include "../clone3/clone3_selftests.h"
     18
     19#ifndef __NR_close_range
     20	#if defined __alpha__
     21		#define __NR_close_range 546
     22	#elif defined _MIPS_SIM
     23		#if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
     24			#define __NR_close_range (436 + 4000)
     25		#endif
     26		#if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
     27			#define __NR_close_range (436 + 6000)
     28		#endif
     29		#if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
     30			#define __NR_close_range (436 + 5000)
     31		#endif
     32	#elif defined __ia64__
     33		#define __NR_close_range (436 + 1024)
     34	#else
     35		#define __NR_close_range 436
     36	#endif
     37#endif
     38
     39#ifndef CLOSE_RANGE_UNSHARE
     40#define CLOSE_RANGE_UNSHARE	(1U << 1)
     41#endif
     42
     43#ifndef CLOSE_RANGE_CLOEXEC
     44#define CLOSE_RANGE_CLOEXEC	(1U << 2)
     45#endif
     46
     47static inline int sys_close_range(unsigned int fd, unsigned int max_fd,
     48				  unsigned int flags)
     49{
     50	return syscall(__NR_close_range, fd, max_fd, flags);
     51}
     52
     53TEST(core_close_range)
     54{
     55	int i, ret;
     56	int open_fds[101];
     57
     58	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
     59		int fd;
     60
     61		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
     62		ASSERT_GE(fd, 0) {
     63			if (errno == ENOENT)
     64				SKIP(return, "Skipping test since /dev/null does not exist");
     65		}
     66
     67		open_fds[i] = fd;
     68	}
     69
     70	EXPECT_EQ(-1, sys_close_range(open_fds[0], open_fds[100], -1)) {
     71		if (errno == ENOSYS)
     72			SKIP(return, "close_range() syscall not supported");
     73	}
     74
     75	EXPECT_EQ(0, sys_close_range(open_fds[0], open_fds[50], 0));
     76
     77	for (i = 0; i <= 50; i++)
     78		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
     79
     80	for (i = 51; i <= 100; i++)
     81		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
     82
     83	/* create a couple of gaps */
     84	close(57);
     85	close(78);
     86	close(81);
     87	close(82);
     88	close(84);
     89	close(90);
     90
     91	EXPECT_EQ(0, sys_close_range(open_fds[51], open_fds[92], 0));
     92
     93	for (i = 51; i <= 92; i++)
     94		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
     95
     96	for (i = 93; i <= 100; i++)
     97		EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
     98
     99	/* test that the kernel caps and still closes all fds */
    100	EXPECT_EQ(0, sys_close_range(open_fds[93], open_fds[99], 0));
    101
    102	for (i = 93; i <= 99; i++)
    103		EXPECT_EQ(-1, fcntl(open_fds[i], F_GETFL));
    104
    105	EXPECT_GT(fcntl(open_fds[i], F_GETFL), -1);
    106
    107	EXPECT_EQ(0, sys_close_range(open_fds[100], open_fds[100], 0));
    108
    109	EXPECT_EQ(-1, fcntl(open_fds[100], F_GETFL));
    110}
    111
    112TEST(close_range_unshare)
    113{
    114	int i, ret, status;
    115	pid_t pid;
    116	int open_fds[101];
    117	struct __clone_args args = {
    118		.flags = CLONE_FILES,
    119		.exit_signal = SIGCHLD,
    120	};
    121
    122	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
    123		int fd;
    124
    125		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
    126		ASSERT_GE(fd, 0) {
    127			if (errno == ENOENT)
    128				SKIP(return, "Skipping test since /dev/null does not exist");
    129		}
    130
    131		open_fds[i] = fd;
    132	}
    133
    134	pid = sys_clone3(&args, sizeof(args));
    135	ASSERT_GE(pid, 0);
    136
    137	if (pid == 0) {
    138		ret = sys_close_range(open_fds[0], open_fds[50],
    139				      CLOSE_RANGE_UNSHARE);
    140		if (ret)
    141			exit(EXIT_FAILURE);
    142
    143		for (i = 0; i <= 50; i++)
    144			if (fcntl(open_fds[i], F_GETFL) != -1)
    145				exit(EXIT_FAILURE);
    146
    147		for (i = 51; i <= 100; i++)
    148			if (fcntl(open_fds[i], F_GETFL) == -1)
    149				exit(EXIT_FAILURE);
    150
    151		/* create a couple of gaps */
    152		close(57);
    153		close(78);
    154		close(81);
    155		close(82);
    156		close(84);
    157		close(90);
    158
    159		ret = sys_close_range(open_fds[51], open_fds[92],
    160				      CLOSE_RANGE_UNSHARE);
    161		if (ret)
    162			exit(EXIT_FAILURE);
    163
    164		for (i = 51; i <= 92; i++)
    165			if (fcntl(open_fds[i], F_GETFL) != -1)
    166				exit(EXIT_FAILURE);
    167
    168		for (i = 93; i <= 100; i++)
    169			if (fcntl(open_fds[i], F_GETFL) == -1)
    170				exit(EXIT_FAILURE);
    171
    172		/* test that the kernel caps and still closes all fds */
    173		ret = sys_close_range(open_fds[93], open_fds[99],
    174				      CLOSE_RANGE_UNSHARE);
    175		if (ret)
    176			exit(EXIT_FAILURE);
    177
    178		for (i = 93; i <= 99; i++)
    179			if (fcntl(open_fds[i], F_GETFL) != -1)
    180				exit(EXIT_FAILURE);
    181
    182		if (fcntl(open_fds[100], F_GETFL) == -1)
    183			exit(EXIT_FAILURE);
    184
    185		ret = sys_close_range(open_fds[100], open_fds[100],
    186				      CLOSE_RANGE_UNSHARE);
    187		if (ret)
    188			exit(EXIT_FAILURE);
    189
    190		if (fcntl(open_fds[100], F_GETFL) != -1)
    191			exit(EXIT_FAILURE);
    192
    193		exit(EXIT_SUCCESS);
    194	}
    195
    196	EXPECT_EQ(waitpid(pid, &status, 0), pid);
    197	EXPECT_EQ(true, WIFEXITED(status));
    198	EXPECT_EQ(0, WEXITSTATUS(status));
    199}
    200
    201TEST(close_range_unshare_capped)
    202{
    203	int i, ret, status;
    204	pid_t pid;
    205	int open_fds[101];
    206	struct __clone_args args = {
    207		.flags = CLONE_FILES,
    208		.exit_signal = SIGCHLD,
    209	};
    210
    211	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
    212		int fd;
    213
    214		fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
    215		ASSERT_GE(fd, 0) {
    216			if (errno == ENOENT)
    217				SKIP(return, "Skipping test since /dev/null does not exist");
    218		}
    219
    220		open_fds[i] = fd;
    221	}
    222
    223	pid = sys_clone3(&args, sizeof(args));
    224	ASSERT_GE(pid, 0);
    225
    226	if (pid == 0) {
    227		ret = sys_close_range(open_fds[0], UINT_MAX,
    228				      CLOSE_RANGE_UNSHARE);
    229		if (ret)
    230			exit(EXIT_FAILURE);
    231
    232		for (i = 0; i <= 100; i++)
    233			if (fcntl(open_fds[i], F_GETFL) != -1)
    234				exit(EXIT_FAILURE);
    235
    236		exit(EXIT_SUCCESS);
    237	}
    238
    239	EXPECT_EQ(waitpid(pid, &status, 0), pid);
    240	EXPECT_EQ(true, WIFEXITED(status));
    241	EXPECT_EQ(0, WEXITSTATUS(status));
    242}
    243
    244TEST(close_range_cloexec)
    245{
    246	int i, ret;
    247	int open_fds[101];
    248	struct rlimit rlimit;
    249
    250	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
    251		int fd;
    252
    253		fd = open("/dev/null", O_RDONLY);
    254		ASSERT_GE(fd, 0) {
    255			if (errno == ENOENT)
    256				SKIP(return, "Skipping test since /dev/null does not exist");
    257		}
    258
    259		open_fds[i] = fd;
    260	}
    261
    262	ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
    263	if (ret < 0) {
    264		if (errno == ENOSYS)
    265			SKIP(return, "close_range() syscall not supported");
    266		if (errno == EINVAL)
    267			SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
    268	}
    269
    270	/* Ensure the FD_CLOEXEC bit is set also with a resource limit in place.  */
    271	ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
    272	rlimit.rlim_cur = 25;
    273	ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
    274
    275	/* Set close-on-exec for two ranges: [0-50] and [75-100].  */
    276	ret = sys_close_range(open_fds[0], open_fds[50], CLOSE_RANGE_CLOEXEC);
    277	ASSERT_EQ(0, ret);
    278	ret = sys_close_range(open_fds[75], open_fds[100], CLOSE_RANGE_CLOEXEC);
    279	ASSERT_EQ(0, ret);
    280
    281	for (i = 0; i <= 50; i++) {
    282		int flags = fcntl(open_fds[i], F_GETFD);
    283
    284		EXPECT_GT(flags, -1);
    285		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    286	}
    287
    288	for (i = 51; i <= 74; i++) {
    289		int flags = fcntl(open_fds[i], F_GETFD);
    290
    291		EXPECT_GT(flags, -1);
    292		EXPECT_EQ(flags & FD_CLOEXEC, 0);
    293	}
    294
    295	for (i = 75; i <= 100; i++) {
    296		int flags = fcntl(open_fds[i], F_GETFD);
    297
    298		EXPECT_GT(flags, -1);
    299		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    300	}
    301
    302	/* Test a common pattern.  */
    303	ret = sys_close_range(3, UINT_MAX, CLOSE_RANGE_CLOEXEC);
    304	for (i = 0; i <= 100; i++) {
    305		int flags = fcntl(open_fds[i], F_GETFD);
    306
    307		EXPECT_GT(flags, -1);
    308		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    309	}
    310}
    311
    312TEST(close_range_cloexec_unshare)
    313{
    314	int i, ret;
    315	int open_fds[101];
    316	struct rlimit rlimit;
    317
    318	for (i = 0; i < ARRAY_SIZE(open_fds); i++) {
    319		int fd;
    320
    321		fd = open("/dev/null", O_RDONLY);
    322		ASSERT_GE(fd, 0) {
    323			if (errno == ENOENT)
    324				SKIP(return, "Skipping test since /dev/null does not exist");
    325		}
    326
    327		open_fds[i] = fd;
    328	}
    329
    330	ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC);
    331	if (ret < 0) {
    332		if (errno == ENOSYS)
    333			SKIP(return, "close_range() syscall not supported");
    334		if (errno == EINVAL)
    335			SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC");
    336	}
    337
    338	/* Ensure the FD_CLOEXEC bit is set also with a resource limit in place.  */
    339	ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
    340	rlimit.rlim_cur = 25;
    341	ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit));
    342
    343	/* Set close-on-exec for two ranges: [0-50] and [75-100].  */
    344	ret = sys_close_range(open_fds[0], open_fds[50],
    345			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
    346	ASSERT_EQ(0, ret);
    347	ret = sys_close_range(open_fds[75], open_fds[100],
    348			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
    349	ASSERT_EQ(0, ret);
    350
    351	for (i = 0; i <= 50; i++) {
    352		int flags = fcntl(open_fds[i], F_GETFD);
    353
    354		EXPECT_GT(flags, -1);
    355		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    356	}
    357
    358	for (i = 51; i <= 74; i++) {
    359		int flags = fcntl(open_fds[i], F_GETFD);
    360
    361		EXPECT_GT(flags, -1);
    362		EXPECT_EQ(flags & FD_CLOEXEC, 0);
    363	}
    364
    365	for (i = 75; i <= 100; i++) {
    366		int flags = fcntl(open_fds[i], F_GETFD);
    367
    368		EXPECT_GT(flags, -1);
    369		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    370	}
    371
    372	/* Test a common pattern.  */
    373	ret = sys_close_range(3, UINT_MAX,
    374			      CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE);
    375	for (i = 0; i <= 100; i++) {
    376		int flags = fcntl(open_fds[i], F_GETFD);
    377
    378		EXPECT_GT(flags, -1);
    379		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    380	}
    381}
    382
    383/*
    384 * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
    385 */
    386TEST(close_range_cloexec_syzbot)
    387{
    388	int fd1, fd2, fd3, flags, ret, status;
    389	pid_t pid;
    390	struct __clone_args args = {
    391		.flags = CLONE_FILES,
    392		.exit_signal = SIGCHLD,
    393	};
    394
    395	/* Create a huge gap in the fd table. */
    396	fd1 = open("/dev/null", O_RDWR);
    397	EXPECT_GT(fd1, 0);
    398
    399	fd2 = dup2(fd1, 1000);
    400	EXPECT_GT(fd2, 0);
    401
    402	pid = sys_clone3(&args, sizeof(args));
    403	ASSERT_GE(pid, 0);
    404
    405	if (pid == 0) {
    406		ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
    407		if (ret)
    408			exit(EXIT_FAILURE);
    409
    410		/*
    411			 * We now have a private file descriptor table and all
    412			 * our open fds should still be open but made
    413			 * close-on-exec.
    414			 */
    415		flags = fcntl(fd1, F_GETFD);
    416		EXPECT_GT(flags, -1);
    417		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    418
    419		flags = fcntl(fd2, F_GETFD);
    420		EXPECT_GT(flags, -1);
    421		EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    422
    423		fd3 = dup2(fd1, 42);
    424		EXPECT_GT(fd3, 0);
    425
    426		/*
    427			 * Duplicating the file descriptor must remove the
    428			 * FD_CLOEXEC flag.
    429			 */
    430		flags = fcntl(fd3, F_GETFD);
    431		EXPECT_GT(flags, -1);
    432		EXPECT_EQ(flags & FD_CLOEXEC, 0);
    433
    434		exit(EXIT_SUCCESS);
    435	}
    436
    437	EXPECT_EQ(waitpid(pid, &status, 0), pid);
    438	EXPECT_EQ(true, WIFEXITED(status));
    439	EXPECT_EQ(0, WEXITSTATUS(status));
    440
    441	/*
    442	 * We had a shared file descriptor table before along with requesting
    443	 * close-on-exec so the original fds must not be close-on-exec.
    444	 */
    445	flags = fcntl(fd1, F_GETFD);
    446	EXPECT_GT(flags, -1);
    447	EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    448
    449	flags = fcntl(fd2, F_GETFD);
    450	EXPECT_GT(flags, -1);
    451	EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    452
    453	fd3 = dup2(fd1, 42);
    454	EXPECT_GT(fd3, 0);
    455
    456	flags = fcntl(fd3, F_GETFD);
    457	EXPECT_GT(flags, -1);
    458	EXPECT_EQ(flags & FD_CLOEXEC, 0);
    459
    460	EXPECT_EQ(close(fd1), 0);
    461	EXPECT_EQ(close(fd2), 0);
    462	EXPECT_EQ(close(fd3), 0);
    463}
    464
    465/*
    466 * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com
    467 */
    468TEST(close_range_cloexec_unshare_syzbot)
    469{
    470	int i, fd1, fd2, fd3, flags, ret, status;
    471	pid_t pid;
    472	struct __clone_args args = {
    473		.flags = CLONE_FILES,
    474		.exit_signal = SIGCHLD,
    475	};
    476
    477	/*
    478	 * Create a huge gap in the fd table. When we now call
    479	 * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper
    480	 * bound the kernel will only copy up to fd1 file descriptors into the
    481	 * new fd table. If the kernel is buggy and doesn't handle
    482	 * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file
    483	 * descriptors and we will oops!
    484	 *
    485	 * On a buggy kernel this should immediately oops. But let's loop just
    486	 * to be sure.
    487	 */
    488	fd1 = open("/dev/null", O_RDWR);
    489	EXPECT_GT(fd1, 0);
    490
    491	fd2 = dup2(fd1, 1000);
    492	EXPECT_GT(fd2, 0);
    493
    494	for (i = 0; i < 100; i++) {
    495
    496		pid = sys_clone3(&args, sizeof(args));
    497		ASSERT_GE(pid, 0);
    498
    499		if (pid == 0) {
    500			ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE |
    501						      CLOSE_RANGE_CLOEXEC);
    502			if (ret)
    503				exit(EXIT_FAILURE);
    504
    505			/*
    506			 * We now have a private file descriptor table and all
    507			 * our open fds should still be open but made
    508			 * close-on-exec.
    509			 */
    510			flags = fcntl(fd1, F_GETFD);
    511			EXPECT_GT(flags, -1);
    512			EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    513
    514			flags = fcntl(fd2, F_GETFD);
    515			EXPECT_GT(flags, -1);
    516			EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC);
    517
    518			fd3 = dup2(fd1, 42);
    519			EXPECT_GT(fd3, 0);
    520
    521			/*
    522			 * Duplicating the file descriptor must remove the
    523			 * FD_CLOEXEC flag.
    524			 */
    525			flags = fcntl(fd3, F_GETFD);
    526			EXPECT_GT(flags, -1);
    527			EXPECT_EQ(flags & FD_CLOEXEC, 0);
    528
    529			EXPECT_EQ(close(fd1), 0);
    530			EXPECT_EQ(close(fd2), 0);
    531			EXPECT_EQ(close(fd3), 0);
    532
    533			exit(EXIT_SUCCESS);
    534		}
    535
    536		EXPECT_EQ(waitpid(pid, &status, 0), pid);
    537		EXPECT_EQ(true, WIFEXITED(status));
    538		EXPECT_EQ(0, WEXITSTATUS(status));
    539	}
    540
    541	/*
    542	 * We created a private file descriptor table before along with
    543	 * requesting close-on-exec so the original fds must not be
    544	 * close-on-exec.
    545	 */
    546	flags = fcntl(fd1, F_GETFD);
    547	EXPECT_GT(flags, -1);
    548	EXPECT_EQ(flags & FD_CLOEXEC, 0);
    549
    550	flags = fcntl(fd2, F_GETFD);
    551	EXPECT_GT(flags, -1);
    552	EXPECT_EQ(flags & FD_CLOEXEC, 0);
    553
    554	fd3 = dup2(fd1, 42);
    555	EXPECT_GT(fd3, 0);
    556
    557	flags = fcntl(fd3, F_GETFD);
    558	EXPECT_GT(flags, -1);
    559	EXPECT_EQ(flags & FD_CLOEXEC, 0);
    560
    561	EXPECT_EQ(close(fd1), 0);
    562	EXPECT_EQ(close(fd2), 0);
    563	EXPECT_EQ(close(fd3), 0);
    564}
    565
    566TEST_HARNESS_MAIN