t_memfd_create.c revision 1.2
1/* $NetBSD: t_memfd_create.c,v 1.2 2023/07/29 16:24:35 rin Exp $ */ 2 3/*- 4 * Copyright (c) 2023 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Theodore Preduta. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#include <sys/cdefs.h> 32__RCSID("$NetBSD: t_memfd_create.c,v 1.2 2023/07/29 16:24:35 rin Exp $"); 33 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/mman.h> 37#include <sys/stat.h> 38#include <errno.h> 39#include <fcntl.h> 40 41#include <atf-c.h> 42 43#include "h_macros.h" 44 45char name_buf[NAME_MAX]; 46char write_buf[8192]; 47char read_buf[8192]; 48 49ATF_TC(create_null_name); 50ATF_TC_HEAD(create_null_name, tc) 51{ 52 53 atf_tc_set_md_var(tc, "descr", 54 "Checks memfd_create fails with EFAULT when invalid memory" 55 " is provided"); 56} 57ATF_TC_BODY(create_null_name, tc) 58{ 59 int fd; 60 61 ATF_REQUIRE_EQ_MSG(fd = memfd_create(NULL, 0), -1, 62 "Unexpected success"); 63 ATF_REQUIRE_ERRNO(EFAULT, true); 64} 65 66ATF_TC(create_long_name); 67ATF_TC_HEAD(create_long_name, tc) 68{ 69 70 atf_tc_set_md_var(tc, "descr", 71 "Checks memfd_create fails for names longer than NAME_MAX-6"); 72} 73ATF_TC_BODY(create_long_name, tc) 74{ 75 int fd; 76 77 memset(name_buf, 'A', sizeof(name_buf)); 78 name_buf[NAME_MAX-6] = '\0'; 79 80 ATF_REQUIRE_EQ_MSG(fd = memfd_create(name_buf, 0), -1, 81 "Unexpected success"); 82 ATF_REQUIRE_ERRNO(ENAMETOOLONG, true); 83 84 name_buf[NAME_MAX-7] = '\0'; 85 86 RL(fd = memfd_create(name_buf, 0)); 87} 88 89ATF_TC(read_write); 90ATF_TC_HEAD(read_write, tc) 91{ 92 93 atf_tc_set_md_var(tc, "descr", 94 "Checks that data can be written to/read from a memfd"); 95} 96ATF_TC_BODY(read_write, tc) 97{ 98 int fd; 99 off_t offset; 100 101 RL(fd = memfd_create("", 0)); 102 103 tests_makegarbage(write_buf, sizeof(write_buf)); 104 memset(read_buf, 0, sizeof(read_buf)); 105 106 RL(write(fd, write_buf, sizeof(write_buf))); 107 offset = lseek(fd, 0, SEEK_CUR); 108 ATF_REQUIRE_EQ_MSG(offset, sizeof(write_buf), 109 "File offset not set after write (%jd != %zu)", (intmax_t)offset, 110 sizeof(write_buf)); 111 112 RZ(lseek(fd, 0, SEEK_SET)); 113 114 RL(read(fd, read_buf, sizeof(read_buf))); 115 offset = lseek(fd, 0, SEEK_CUR); 116 ATF_REQUIRE_EQ_MSG(offset, sizeof(read_buf), 117 "File offset not set after read (%jd != %zu)", (intmax_t)offset, 118 sizeof(read_buf)); 119 120 for (size_t i = 0; i < sizeof(read_buf); i++) 121 ATF_REQUIRE_EQ_MSG(read_buf[i], write_buf[i], 122 "Data read does not match data written"); 123} 124 125ATF_TC(truncate); 126ATF_TC_HEAD(truncate, tc) 127{ 128 129 atf_tc_set_md_var(tc, "descr", 130 "Checks that truncation does result in data removal"); 131} 132ATF_TC_BODY(truncate, tc) 133{ 134 int fd; 135 struct stat st; 136 137 RL(fd = memfd_create("", 0)); 138 139 tests_makegarbage(write_buf, sizeof(write_buf)); 140 tests_makegarbage(read_buf, sizeof(read_buf)); 141 142 RL(write(fd, write_buf, sizeof(write_buf))); 143 144 RL(fstat(fd, &st)); 145 ATF_REQUIRE_EQ_MSG(st.st_size, sizeof(write_buf), 146 "Write did not grow size to %zu (is %jd)", sizeof(write_buf), 147 (intmax_t)st.st_size); 148 149 RL(ftruncate(fd, sizeof(write_buf)/2)); 150 RL(fstat(fd, &st)); 151 ATF_REQUIRE_EQ_MSG(st.st_size, sizeof(write_buf)/2, 152 "Truncate did not shrink size to %zu (is %jd)", 153 sizeof(write_buf)/2, (intmax_t)st.st_size); 154 155 RL(ftruncate(fd, sizeof(read_buf))); 156 RL(fstat(fd, &st)); 157 ATF_REQUIRE_EQ_MSG(st.st_size, sizeof(read_buf), 158 "Truncate did not grow size to %zu (is %jd)", sizeof(read_buf), 159 (intmax_t)st.st_size); 160 161 RZ(lseek(fd, 0, SEEK_SET)); 162 RL(read(fd, read_buf, sizeof(read_buf))); 163 164 for (size_t i = 0; i < sizeof(read_buf)/2; i++) 165 ATF_REQUIRE_EQ_MSG(read_buf[i], write_buf[i], 166 "Data read does not match data written"); 167 for (size_t i = sizeof(read_buf)/2; i < sizeof(read_buf); i++) 168 ATF_REQUIRE_EQ_MSG(read_buf[i], 0, 169 "Data read on growed region is not zeroed"); 170} 171 172ATF_TC(mmap); 173ATF_TC_HEAD(mmap, tc) 174{ 175 176 atf_tc_set_md_var(tc, "descr", "Check that mmap succeeds"); 177} 178ATF_TC_BODY(mmap, tc) 179{ 180 int fd; 181 void *addr; 182 183 RL(fd = memfd_create("", 0)); 184 RL(ftruncate(fd, sizeof(read_buf))); 185 186 addr = mmap(NULL, sizeof(read_buf), PROT_READ|PROT_WRITE, MAP_SHARED, 187 fd, 0); 188 ATF_REQUIRE_MSG(addr != MAP_FAILED, "Mmap failed unexpectedly (%s)", 189 strerror(errno)); 190} 191 192ATF_TC(create_no_sealing); 193ATF_TC_HEAD(create_no_sealing, tc) 194{ 195 196 atf_tc_set_md_var(tc, "descr", 197 "Checks that seals cannot be added if MFD_ALLOW_SEALING is" 198 " not specified to memfd_create"); 199} 200ATF_TC_BODY(create_no_sealing, tc) 201{ 202 int fd; 203 204 RL(fd = memfd_create("", 0)); 205 206 ATF_REQUIRE_EQ_MSG(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE), -1, 207 "fcntl succeeded unexpectedly"); 208 ATF_REQUIRE_ERRNO(EPERM, true); 209} 210 211ATF_TC(seal_seal); 212ATF_TC_HEAD(seal_seal, tc) 213{ 214 215 atf_tc_set_md_var(tc, "descr", 216 "Checks adding F_SEAL_SEAL prevents adding other seals"); 217} 218ATF_TC_BODY(seal_seal, tc) 219{ 220 int fd; 221 222 RL(fd = memfd_create("", MFD_ALLOW_SEALING)); 223 RL(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL)); 224 225 ATF_REQUIRE_EQ_MSG(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE), -1, 226 "fcntl succeeded unexpectedly"); 227 ATF_REQUIRE_ERRNO(EPERM, true); 228} 229 230/* 231 * Tests that the seals provided in except to not also prevent some 232 * other operation. 233 * 234 * Note: fd must have a positive size. 235 */ 236static void 237test_all_seals_except(int fd, int except) 238{ 239 int rv; 240 struct stat st; 241 void *addr; 242 243 RL(fstat(fd, &st)); 244 ATF_REQUIRE(st.st_size > 0); 245 246 if (except & ~F_SEAL_SEAL) { 247 rv = fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL); 248 if (rv == -1) { 249 ATF_REQUIRE_MSG(errno != EPERM, 250 "Seal %x prevented F_ADD_SEALS", except); 251 ATF_REQUIRE_MSG(errno == EPERM, 252 "F_ADD_SEALS failed unexpectedly (%s)", 253 strerror(errno)); 254 } 255 } 256 257 if (except & ~(F_SEAL_WRITE|F_SEAL_FUTURE_WRITE)) { 258 RZ(lseek(fd, 0, SEEK_SET)); 259 rv = write(fd, write_buf, sizeof(write_buf)); 260 if (rv == -1) { 261 ATF_REQUIRE_MSG(errno != EPERM, 262 "Seal %x prevented write", except); 263 ATF_REQUIRE_MSG(errno == EPERM, 264 "Write failed unexpectedly (%s)", 265 strerror(errno)); 266 } 267 268 addr = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, 269 MAP_SHARED, fd, 0); 270 ATF_REQUIRE_MSG(addr != MAP_FAILED, 271 "Mmap failed unexpectedly (%s)", strerror(errno)); 272 } 273 274 if (except & ~F_SEAL_SHRINK) { 275 rv = ftruncate(fd, st.st_size - 1); 276 if (rv == -1) { 277 ATF_REQUIRE_MSG(errno != EPERM, 278 "Seal %x prevented truncate to shrink", except); 279 ATF_REQUIRE_MSG(errno == EPERM, 280 "Truncate failed unexpectedly (%s)", 281 strerror(errno)); 282 } 283 } 284 285 if (except & ~F_SEAL_GROW) { 286 rv = ftruncate(fd, st.st_size + 1); 287 if (rv == -1) { 288 ATF_REQUIRE_MSG(errno != EPERM, 289 "Seal %x prevented truncate to shrink", except); 290 ATF_REQUIRE_MSG(errno == EPERM, 291 "Truncate failed unexpectedly (%s)", 292 strerror(errno)); 293 } 294 } 295} 296 297ATF_TC(seal_shrink); 298ATF_TC_HEAD(seal_shrink, tc) 299{ 300 301 atf_tc_set_md_var(tc, "descr", 302 "Checks F_SEAL_SHRINK prevents shrinking the file"); 303} 304ATF_TC_BODY(seal_shrink, tc) 305{ 306 int fd; 307 308 RL(fd = memfd_create("", MFD_ALLOW_SEALING)); 309 RL(ftruncate(fd, sizeof(write_buf))); 310 RL(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK)); 311 312 ATF_REQUIRE_EQ_MSG(ftruncate(fd, sizeof(write_buf)/2), -1, 313 "Truncate succeeded unexpectedly"); 314 ATF_REQUIRE_ERRNO(EPERM, true); 315 316 test_all_seals_except(fd, F_SEAL_SHRINK); 317} 318 319ATF_TC(seal_grow); 320ATF_TC_HEAD(seal_grow, tc) 321{ 322 323 atf_tc_set_md_var(tc, "descr", 324 "Checks F_SEAL_SHRINK prevents growing the file"); 325} 326ATF_TC_BODY(seal_grow, tc) 327{ 328 int fd; 329 330 RL(fd = memfd_create("", MFD_ALLOW_SEALING)); 331 RL(ftruncate(fd, sizeof(write_buf)/2)); 332 RL(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW)); 333 334 ATF_REQUIRE_EQ_MSG(ftruncate(fd, sizeof(write_buf)), -1, 335 "Truncate succeeded unexpectedly"); 336 ATF_REQUIRE_ERRNO(EPERM, true); 337 338 test_all_seals_except(fd, F_SEAL_GROW); 339} 340 341ATF_TC(seal_write); 342ATF_TC_HEAD(seal_write, tc) 343{ 344 345 atf_tc_set_md_var(tc, "descr", 346 "Checks F_SEAL_WRITE prevents writing"); 347} 348ATF_TC_BODY(seal_write, tc) 349{ 350 int fd; 351 352 RL(fd = memfd_create("", MFD_ALLOW_SEALING)); 353 RL(ftruncate(fd, sizeof(write_buf)/2)); 354 RL(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE)); 355 356 ATF_REQUIRE_EQ_MSG(write(fd, write_buf, sizeof(write_buf)), -1, 357 "Write succeeded unexpectedly"); 358 ATF_REQUIRE_ERRNO(EPERM, true); 359 360 test_all_seals_except(fd, F_SEAL_WRITE); 361} 362 363ATF_TC(seal_write_mmap); 364ATF_TC_HEAD(seal_write_mmap, tc) 365{ 366 367 atf_tc_set_md_var(tc, "descr", 368 "Checks that F_SEAL_WRITE cannot be added with open mmaps"); 369} 370ATF_TC_BODY(seal_write_mmap, tc) 371{ 372 int fd; 373 void *addr; 374 375 RL(fd = memfd_create("", MFD_ALLOW_SEALING)); 376 RL(ftruncate(fd, sizeof(read_buf))); 377 378 addr = mmap(NULL, sizeof(read_buf), PROT_READ|PROT_WRITE, MAP_SHARED, 379 fd, 0); 380 ATF_REQUIRE_MSG(addr != MAP_FAILED, "Mmap failed unexpectedly (%s)", 381 strerror(errno)); 382 383 ATF_REQUIRE_EQ_MSG(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE), -1, 384 "fcntl succeeded unexpectedly"); 385 ATF_REQUIRE_ERRNO(EBUSY, true); 386} 387 388ATF_TC(seal_future_write); 389ATF_TC_HEAD(seal_future_write, tc) 390{ 391 392 atf_tc_set_md_var(tc, "descr", 393 "Checks F_SEAL_FUTURE_WRITE prevents writing"); 394} 395ATF_TC_BODY(seal_future_write, tc) 396{ 397 int fd; 398 399 RL(fd = memfd_create("", MFD_ALLOW_SEALING)); 400 RL(ftruncate(fd, sizeof(write_buf)/2)); 401 RL(fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE)); 402 403 ATF_REQUIRE_EQ_MSG(write(fd, write_buf, sizeof(write_buf)), -1, 404 "Write succeeded unexpectedly"); 405 ATF_REQUIRE_ERRNO(EPERM, true); 406 407 test_all_seals_except(fd, F_SEAL_FUTURE_WRITE); 408} 409 410ATF_TC(seal_future_write_mmap); 411ATF_TC_HEAD(seal_future_write_mmap, tc) 412{ 413 414 atf_tc_set_md_var(tc, "descr", 415 "Checks that F_SEAL_WRITE can be added with open mmaps but" 416 " prevents creating new ones"); 417} 418ATF_TC_BODY(seal_future_write_mmap, tc) 419{ 420 int fd; 421 void *addr; 422 423 RL(fd = memfd_create("", MFD_ALLOW_SEALING)); 424 RL(ftruncate(fd, sizeof(read_buf))); 425 addr = mmap(NULL, sizeof(read_buf), PROT_READ|PROT_WRITE, MAP_SHARED, 426 fd, 0); 427 ATF_REQUIRE_MSG(addr != MAP_FAILED, "Mmap failed unexpectedly (%s)", 428 strerror(errno)); 429 430 RL(fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE)); 431 432 ATF_REQUIRE_EQ_MSG(mmap(NULL, sizeof(read_buf), PROT_READ|PROT_WRITE, 433 MAP_SHARED, fd, 0), MAP_FAILED, "Mmap succeeded unexpectedly"); 434 ATF_REQUIRE_ERRNO(EPERM, true); 435} 436 437 438ATF_TP_ADD_TCS(tp) 439{ 440 ATF_TP_ADD_TC(tp, create_null_name); 441 ATF_TP_ADD_TC(tp, create_long_name); 442 ATF_TP_ADD_TC(tp, read_write); 443 ATF_TP_ADD_TC(tp, truncate); 444 ATF_TP_ADD_TC(tp, mmap); 445 ATF_TP_ADD_TC(tp, create_no_sealing); 446 ATF_TP_ADD_TC(tp, seal_seal); 447 ATF_TP_ADD_TC(tp, seal_shrink); 448 ATF_TP_ADD_TC(tp, seal_grow); 449 ATF_TP_ADD_TC(tp, seal_write); 450 ATF_TP_ADD_TC(tp, seal_write_mmap); 451 ATF_TP_ADD_TC(tp, seal_future_write); 452 ATF_TP_ADD_TC(tp, seal_future_write_mmap); 453 454 return atf_no_error(); 455} 456