Home | History | Annotate | Download | only in memfd_create
      1 /*
      2  * Copyright (C) 2017  Red Hat, Inc.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of
      7  * the License, or (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it would be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  */
     15 
     16 #define _GNU_SOURCE
     17 
     18 #include <sys/types.h>
     19 #include <sys/syscall.h>
     20 #include <sys/uio.h>
     21 #include <errno.h>
     22 #include <string.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <unistd.h>
     26 
     27 #define TST_NO_DEFAULT_MAIN
     28 #include "tst_test.h"
     29 #include "lapi/fallocate.h"
     30 #include "lapi/fcntl.h"
     31 #include "lapi/memfd.h"
     32 
     33 #include "lapi/syscalls.h"
     34 
     35 #include "memfd_create_common.h"
     36 
     37 int sys_memfd_create(const char *name, unsigned int flags)
     38 {
     39 	return tst_syscall(__NR_memfd_create, name, flags);
     40 }
     41 
     42 int check_fallocate(const char *filename, const int lineno, int fd,
     43 			int mode, off_t offset, off_t len)
     44 {
     45 	int r;
     46 
     47 	r = fallocate(fd, mode, offset, len);
     48 	if (r < 0) {
     49 		tst_brk_(filename, lineno, TFAIL | TERRNO,
     50 			"fallocate(%d, %d, %ld, %ld) failed", fd, mode,
     51 			offset, len);
     52 	}
     53 
     54 	tst_res_(filename, lineno, TPASS,
     55 		"fallocate(%d, %d, %ld, %ld) succeeded", fd, mode,
     56 		offset, len);
     57 
     58 	return r;
     59 }
     60 
     61 int check_fallocate_fail(const char *filename, const int lineno, int fd,
     62 				int mode, off_t offset, off_t len)
     63 {
     64 	int r;
     65 
     66 	r = fallocate(fd, mode, offset, len);
     67 	if (r >= 0) {
     68 		tst_res_(filename, lineno, TFAIL,
     69 			"fallocate(%d, %d, %ld, %ld) succeeded unexpectedly",
     70 			fd, mode, offset, len);
     71 
     72 		return r;
     73 	}
     74 
     75 	tst_res_(filename, lineno, TPASS | TERRNO,
     76 		"fallocate(%d, %d, %ld, %ld) failed as expected", fd,
     77 		mode, offset, len);
     78 
     79 	return r;
     80 }
     81 
     82 void check_ftruncate(const char *filename, const int lineno, int fd,
     83 			off_t length)
     84 {
     85 	safe_ftruncate(filename, lineno, fd, length);
     86 
     87 	tst_res_(filename, lineno, TPASS, "ftruncate(%d, %ld) succeeded", fd,
     88 		length);
     89 }
     90 
     91 void check_ftruncate_fail(const char *filename, const int lineno,
     92 				int fd, off_t length)
     93 {
     94 	if (ftruncate(fd, length) >= 0) {
     95 		tst_res_(filename, lineno, TFAIL,
     96 			"ftruncate(%d, %ld) succeeded unexpectedly",
     97 			fd, length);
     98 
     99 		return;
    100 	}
    101 
    102 	tst_res_(filename, lineno, TPASS | TERRNO,
    103 		"ftruncate(%d, %ld) failed as expected", fd, length);
    104 }
    105 
    106 int get_mfd_all_available_flags(const char *filename, const int lineno)
    107 {
    108 	unsigned int i;
    109 	int flag;
    110 	int flags2test[] = FLAGS_ALL_ARRAY_INITIALIZER;
    111 	int flags_available = 0;
    112 
    113 	if (!MFD_FLAGS_AVAILABLE(0)) {
    114 		tst_brk_(filename, lineno, TCONF,
    115 				"memfd_create(0) not implemented");
    116 	}
    117 
    118 	for (i = 0; i < ARRAY_SIZE(flags2test); i++) {
    119 		flag = flags2test[i];
    120 
    121 		if (MFD_FLAGS_AVAILABLE(flag))
    122 			flags_available |= flag;
    123 	}
    124 
    125 	return flags_available;
    126 }
    127 
    128 int mfd_flags_available(const char *filename, const int lineno,
    129 		unsigned int flags)
    130 {
    131 	TEST(sys_memfd_create("dummy_call", flags));
    132 	if (TEST_RETURN < 0) {
    133 		if (TEST_ERRNO != EINVAL) {
    134 			tst_brk_(filename, lineno, TBROK | TTERRNO,
    135 					"memfd_create() failed");
    136 		}
    137 
    138 		return 0;
    139 	}
    140 
    141 	SAFE_CLOSE(TEST_RETURN);
    142 
    143 	return 1;
    144 }
    145 
    146 int check_mfd_new(const char *filename, const int lineno,
    147 			const char *name, loff_t sz, int flags)
    148 {
    149 	int fd;
    150 
    151 	fd = sys_memfd_create(name, flags);
    152 	if (fd < 0) {
    153 		tst_brk_(filename, lineno, TBROK | TERRNO,
    154 			"memfd_create(%s, %d) failed", name, flags);
    155 	}
    156 
    157 	tst_res_(filename, lineno, TPASS, "memfd_create(%s, %d) succeeded",
    158 		name, flags);
    159 
    160 	check_ftruncate(filename, lineno, fd, sz);
    161 
    162 	return fd;
    163 }
    164 
    165 void check_mfd_fail_new(const char *filename, const int lineno,
    166 			const char *name, int flags)
    167 {
    168 	int fd;
    169 
    170 	fd = sys_memfd_create(name, flags);
    171 	if (fd >= 0) {
    172 		safe_close(filename, lineno, NULL, fd);
    173 		tst_brk_(filename, lineno, TFAIL,
    174 			 "memfd_create(%s, %d) succeeded unexpectedly",
    175 			name, flags);
    176 	}
    177 
    178 	tst_res_(filename, lineno, TPASS | TERRNO,
    179 		"memfd_create(%s, %d) failed as expected", name, flags);
    180 }
    181 
    182 void *check_mmap(const char *file, const int lineno, void *addr, size_t length,
    183 		int prot, int flags, int fd, off_t offset)
    184 {
    185 	void *p;
    186 
    187 	p = safe_mmap(file, lineno, addr, length, prot, flags, fd, offset);
    188 
    189 	tst_res_(file, lineno, TPASS,
    190 		"mmap(%p, %zu, %i, %i, %i, %li) succeeded", addr,
    191 		length, prot, flags, fd, (long)offset);
    192 
    193 	return p;
    194 }
    195 
    196 void check_mmap_fail(const char *file, const int lineno, void *addr,
    197 		size_t length, int prot, int flags, int fd, off_t offset)
    198 {
    199 	if (mmap(addr, length, prot, flags, fd, offset) != MAP_FAILED) {
    200 		safe_munmap(file, lineno, NULL, addr, length);
    201 		tst_res_(file, lineno, TFAIL,
    202 			"mmap(%p, %zu, %i, %i, %i, %li) succeeded unexpectedly",
    203 			addr, length, prot, flags, fd, (long)offset);
    204 
    205 		return;
    206 	}
    207 
    208 	tst_res_(file, lineno, TPASS | TERRNO,
    209 		"mmap(%p, %zu, %i, %i, %i, %li) failed as expected",
    210 		addr, length, prot, flags, fd, (long)offset);
    211 }
    212 
    213 void check_munmap(const char *file, const int lineno, void *p, size_t length)
    214 {
    215 	safe_munmap(file, lineno, NULL, p, length);
    216 
    217 	tst_res_(file, lineno, TPASS, "munmap(%p, %zu) succeeded", p, length);
    218 }
    219 
    220 void check_mfd_has_seals(const char *file, const int lineno, int fd, int seals)
    221 {
    222 	int ret = SAFE_FCNTL((fd), F_GET_SEALS);
    223 	if (ret	!= seals) {
    224 		tst_brk_(file, lineno, TFAIL,
    225 			"fd %d doesn't have expected seals (%d expected %d)",
    226 			fd, ret, seals);
    227 	}
    228 
    229 	tst_res_(file, lineno, TPASS,
    230 		 "fd %d has expected seals (%d)", fd, seals);
    231 }
    232 
    233 void check_mprotect(const char *file, const int lineno, void *addr,
    234 		size_t length, int prot)
    235 {
    236 	if (mprotect(addr, length, prot) < 0) {
    237 		tst_brk_(file, lineno, TFAIL | TERRNO,
    238 			"mprotect(%p, %zu, %d) failed", addr, length, prot);
    239 	}
    240 
    241 	tst_res_(file, lineno, TPASS, "mprotect(%p, %zu, %d) succeeded", addr,
    242 		length, prot);
    243 }
    244 
    245 void check_mfd_fail_add_seals(const char *filename, const int lineno,
    246 				int fd, int seals)
    247 {
    248 	if (fcntl(fd, F_ADD_SEALS, seals) >= 0) {
    249 		tst_brk_(filename, lineno, TFAIL,
    250 			"fcntl(%d, F_ADD_SEALS) succeeded unexpectedly", fd);
    251 	}
    252 
    253 	tst_res_(filename, lineno, TPASS | TERRNO,
    254 		"fcntl(%d, F_ADD_SEALS, %d) failed as expected", (fd),
    255 		(seals));
    256 }
    257 
    258 void check_mfd_size(const char *filename, const int lineno, int fd,
    259 			size_t size)
    260 {
    261 	struct stat st;
    262 
    263 	safe_fstat(filename, lineno, fd, &st);
    264 
    265 	if (st.st_size != (long)size) {
    266 		tst_brk_(filename, lineno, TFAIL,
    267 			"fstat(%d, &st): unexpected file size", fd);
    268 	}
    269 
    270 	tst_res_(filename, lineno, TPASS,
    271 		"fstat(%d, &st): file size is correct", fd);
    272 }
    273 
    274 int check_mfd_open(const char *filename, const int lineno, int fd,
    275 			int flags, mode_t mode)
    276 {
    277 	int r;
    278 	char buf[512];
    279 
    280 	sprintf(buf, "/proc/self/fd/%d", fd);
    281 
    282 	r = safe_open(filename, lineno, NULL, buf, flags, mode);
    283 
    284 	tst_res_(filename, lineno, TPASS, "open(%s, %d, %d) succeeded", buf,
    285 		flags, mode);
    286 
    287 	return r;
    288 }
    289 
    290 void check_mfd_fail_open(const char *filename, const int lineno, int fd,
    291 				int flags, mode_t mode)
    292 {
    293 	char buf[512];
    294 
    295 	sprintf(buf, "/proc/self/fd/%d", fd);
    296 
    297 	fd = open(buf, flags, mode);
    298 	if (fd > 0) {
    299 		safe_close(filename, lineno, NULL, fd);
    300 		tst_res_(filename, lineno, TFAIL,
    301 			"open(%s, %d, %d) succeeded unexpectedly", buf,
    302 			flags, mode);
    303 	} else {
    304 		tst_res_(filename, lineno, TPASS | TERRNO,
    305 			"open(%s, %d, %d) failed as expected", buf,
    306 			flags, mode);
    307 	}
    308 }
    309 
    310 void check_mfd_readable(const char *filename, const int lineno, int fd)
    311 {
    312 	char buf[16];
    313 	void *p;
    314 
    315 	safe_read(filename, lineno, NULL, 1, fd, buf, sizeof(buf));
    316 	tst_res_(filename, lineno, TPASS, "read(%d, %s, %zu) succeeded", fd,
    317 		buf, sizeof(buf));
    318 
    319 	/* verify PROT_READ *is* allowed */
    320 	p = check_mmap(filename, lineno, NULL, MFD_DEF_SIZE, PROT_READ,
    321 			MAP_PRIVATE, fd, 0);
    322 
    323 	check_munmap(filename, lineno, p, MFD_DEF_SIZE);
    324 
    325 	/* verify MAP_PRIVATE is *always* allowed (even writable) */
    326 	p = check_mmap(filename, lineno, NULL, MFD_DEF_SIZE,
    327 			PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    328 
    329 	check_munmap(filename, lineno, p, MFD_DEF_SIZE);
    330 }
    331 
    332 void check_mfd_writeable(const char *filename, const int lineno, int fd)
    333 {
    334 	void *p;
    335 
    336 	/* verify write() succeeds */
    337 	safe_write(filename, lineno, NULL, 1, fd, "\0\0\0\0", 4);
    338 	tst_res_(filename, lineno, TPASS, "write(%d, %s, %d) succeeded", fd,
    339 		"\\0\\0\\0\\0", 4);
    340 
    341 	/* verify PROT_READ | PROT_WRITE is allowed */
    342 	p = check_mmap(filename, lineno, NULL, MFD_DEF_SIZE,
    343 			PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    344 
    345 	*(char *)p = 0;
    346 	check_munmap(filename, lineno, p, MFD_DEF_SIZE);
    347 
    348 	/* verify PROT_WRITE is allowed */
    349 	p = check_mmap(filename, lineno, NULL, MFD_DEF_SIZE,
    350 			PROT_WRITE, MAP_SHARED, fd, 0);
    351 
    352 	*(char *)p = 0;
    353 	check_munmap(filename, lineno, p, MFD_DEF_SIZE);
    354 
    355 	/* verify PROT_READ with MAP_SHARED is allowed and a following
    356 	 * mprotect(PROT_WRITE) allows writing
    357 	 */
    358 	p = check_mmap(filename, lineno, NULL, MFD_DEF_SIZE,
    359 			PROT_READ, MAP_SHARED, fd, 0);
    360 
    361 	check_mprotect(filename, lineno, p, MFD_DEF_SIZE,
    362 			PROT_READ | PROT_WRITE);
    363 
    364 	*(char *)p = 0;
    365 	check_munmap(filename, lineno, p, MFD_DEF_SIZE);
    366 
    367 	/* verify PUNCH_HOLE works */
    368 	check_fallocate(filename, lineno, fd,
    369 			FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0,
    370 			MFD_DEF_SIZE);
    371 }
    372 
    373 void check_mfd_non_writeable(const char *filename, const int lineno,
    374 				int fd)
    375 {
    376 	void *p;
    377 
    378 	/* verify write() fails */
    379 	TEST(write(fd, "data", 4));
    380 	if (TEST_RETURN < 0) {
    381 		if (TEST_ERRNO != EPERM) {
    382 			tst_brk_(filename, lineno, TFAIL | TTERRNO,
    383 				"write() didn't fail as expected");
    384 		}
    385 	} else {
    386 		tst_brk_(filename, lineno, TFAIL,
    387 			"write() succeeded unexpectedly");
    388 	}
    389 	tst_res_(filename, lineno, TPASS | TTERRNO, "write failed as expected");
    390 
    391 	/* verify PROT_READ | PROT_WRITE is not allowed */
    392 	check_mmap_fail(filename, lineno, NULL, MFD_DEF_SIZE,
    393 			PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    394 
    395 	/* verify PROT_WRITE is not allowed */
    396 	check_mmap_fail(filename, lineno, NULL, MFD_DEF_SIZE,
    397 			PROT_WRITE, MAP_SHARED, fd, 0);
    398 
    399 	/* Verify PROT_READ with MAP_SHARED with a following mprotect is not
    400 	 * allowed. Note that for r/w the kernel already prevents the mmap.
    401 	 */
    402 	p = mmap(NULL, MFD_DEF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
    403 	if (p != MAP_FAILED) {
    404 		if (mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE) >= 0) {
    405 			tst_brk_(filename, lineno, TFAIL | TERRNO,
    406 				"mmap()+mprotect() succeeded unexpectedly");
    407 		}
    408 	}
    409 
    410 	/* verify PUNCH_HOLE fails */
    411 	check_fallocate_fail(filename, lineno, fd,
    412 			FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0,
    413 			MFD_DEF_SIZE);
    414 }
    415 
    416 void check_mfd_shrinkable(const char *filename, const int lineno, int fd)
    417 {
    418 	int fd2;
    419 
    420 	check_ftruncate(filename, lineno, fd, MFD_DEF_SIZE / 2);
    421 	check_mfd_size(filename, lineno, fd, MFD_DEF_SIZE / 2);
    422 
    423 	fd2 = check_mfd_open(filename, lineno, fd,
    424 			O_RDWR | O_CREAT | O_TRUNC, 0600);
    425 	safe_close(filename, lineno, NULL, fd2);
    426 
    427 	check_mfd_size(filename, lineno, fd, 0);
    428 }
    429 
    430 void check_mfd_non_shrinkable(const char *filename, const int lineno, int fd)
    431 {
    432 	check_ftruncate_fail(filename, lineno, fd,  MFD_DEF_SIZE / 2);
    433 	check_mfd_fail_open(filename, lineno, fd,
    434 			O_RDWR | O_CREAT | O_TRUNC, 0600);
    435 }
    436 
    437 void check_mfd_growable(const char *filename, const int lineno, int fd)
    438 {
    439 	check_ftruncate(filename, lineno, fd, MFD_DEF_SIZE * 2);
    440 	check_mfd_size(filename, lineno, fd, MFD_DEF_SIZE * 2);
    441 
    442 	check_fallocate(filename, lineno, fd, 0, 0, MFD_DEF_SIZE * 4);
    443 	check_mfd_size(filename, lineno, fd, MFD_DEF_SIZE * 4);
    444 }
    445 
    446 void check_mfd_non_growable(const char *filename, const int lineno, int fd)
    447 {
    448 	check_ftruncate_fail(filename, lineno, fd, MFD_DEF_SIZE * 2);
    449 	check_fallocate_fail(filename, lineno, fd, 0, 0, MFD_DEF_SIZE * 4);
    450 }
    451 
    452 void check_mfd_growable_by_write(const char *filename, const int lineno, int fd)
    453 {
    454 	char buf[MFD_DEF_SIZE * 8];
    455 
    456 	if (pwrite(fd, buf, sizeof(buf), 0) != sizeof(buf)) {
    457 		tst_res_(filename, lineno, TFAIL | TERRNO,
    458 			"pwrite(%d, %s, %zu, %d) failed",
    459 			fd, buf, sizeof(buf), 0);
    460 
    461 		return;
    462 	}
    463 
    464 	tst_res_(filename, lineno, TPASS, "pwrite(%d, %s, %zu, %d) succeeded",
    465 		fd, buf, sizeof(buf), 0);
    466 
    467 	check_mfd_size(filename, lineno, fd, MFD_DEF_SIZE * 8);
    468 }
    469 
    470 void check_mfd_non_growable_by_write(const char *filename, const int lineno,
    471 					int fd)
    472 {
    473 	char buf[MFD_DEF_SIZE * 8];
    474 
    475 	if (pwrite(fd, buf, sizeof(buf), 0) == sizeof(buf)) {
    476 		tst_res_(filename, lineno, TFAIL,
    477 			"pwrite(%d, %s, %zu, %d) didn't fail as expected",
    478 			fd, buf, sizeof(buf), 0);
    479 
    480 		return;
    481 	}
    482 
    483 	tst_res_(filename, lineno, TPASS, "pwrite(%d, %s, %zu, %d) succeeded",
    484 		fd, buf, sizeof(buf), 0);
    485 }
    486