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 (TST_RET < 0) { 133 if (TST_ERR != EINVAL) { 134 tst_brk_(filename, lineno, TBROK | TTERRNO, 135 "memfd_create() failed"); 136 } 137 138 return 0; 139 } 140 141 SAFE_CLOSE(TST_RET); 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 (TST_RET < 0) { 381 if (TST_ERR != 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