1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/fcntl.h> 32 #include <sys/mman.h> 33 #include <sys/stat.h> 34 35 #include <atf-c.h> 36 #include <errno.h> 37 #include <unistd.h> 38 39 ATF_TC_WITHOUT_HEAD(basic); 40 ATF_TC_BODY(basic, tc) 41 { 42 struct stat sb; 43 int fd; 44 char buf[8]; 45 46 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1); 47 48 /* write(2) should grow us out automatically. */ 49 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf)); 50 ATF_REQUIRE(fstat(fd, &sb) == 0); 51 ATF_REQUIRE(sb.st_size == sizeof(buf)); 52 53 /* ftruncate(2) must succeed without seals */ 54 ATF_REQUIRE(ftruncate(fd, 2 * (sizeof(buf) - 1)) == 0); 55 56 /* write(2) again must not be limited by ftruncate(2) size. */ 57 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf)); 58 59 /* Sanity check. */ 60 ATF_REQUIRE(fstat(fd, &sb) == 0); 61 ATF_REQUIRE(sb.st_size == 2 * sizeof(buf)); 62 63 close(fd); 64 } 65 66 ATF_TC_WITHOUT_HEAD(cloexec); 67 ATF_TC_BODY(cloexec, tc) 68 { 69 int fd_nocl, fd_cl; 70 71 ATF_REQUIRE((fd_nocl = memfd_create("...", 0)) != -1); 72 ATF_REQUIRE((fd_cl = memfd_create("...", MFD_CLOEXEC)) != -1); 73 74 ATF_REQUIRE((fcntl(fd_nocl, F_GETFD) & FD_CLOEXEC) == 0); 75 ATF_REQUIRE((fcntl(fd_cl, F_GETFD) & FD_CLOEXEC) != 0); 76 77 close(fd_nocl); 78 close(fd_cl); 79 } 80 81 ATF_TC_WITHOUT_HEAD(disallowed_sealing); 82 ATF_TC_BODY(disallowed_sealing, tc) 83 { 84 int fd; 85 86 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1); 87 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == F_SEAL_SEAL); 88 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); 89 ATF_REQUIRE(errno == EPERM); 90 91 close(fd); 92 } 93 94 #define BUF_SIZE 1024 95 96 ATF_TC_WITHOUT_HEAD(write_seal); 97 ATF_TC_BODY(write_seal, tc) 98 { 99 int fd; 100 char *addr, buf[BUF_SIZE]; 101 102 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 103 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0); 104 105 /* Write once, then we'll seal it and try again */ 106 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == BUF_SIZE); 107 ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0); 108 109 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); 110 ATF_REQUIRE(addr != MAP_FAILED); 111 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0); 112 113 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0); 114 115 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == -1); 116 ATF_REQUIRE(errno == EPERM); 117 118 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, 119 fd, 0) == MAP_FAILED); 120 ATF_REQUIRE(errno == EACCES); 121 122 close(fd); 123 } 124 125 ATF_TC_WITHOUT_HEAD(mmap_write_seal); 126 ATF_TC_BODY(mmap_write_seal, tc) 127 { 128 int fd; 129 char *addr, *paddr, *raddr; 130 131 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 132 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0); 133 134 /* Map it, both shared and privately */ 135 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0); 136 ATF_REQUIRE(addr != MAP_FAILED); 137 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); 138 ATF_REQUIRE(paddr != MAP_FAILED); 139 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0); 140 ATF_REQUIRE(raddr != MAP_FAILED); 141 142 /* Now try to seal it before unmapping */ 143 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); 144 ATF_REQUIRE(errno == EBUSY); 145 146 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0); 147 148 /* 149 * This should fail, because raddr still exists and it was spawned from 150 * a r/w fd. 151 */ 152 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); 153 ATF_REQUIRE(errno == EBUSY); 154 155 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0); 156 /* This one should succeed; only the private mapping remains. */ 157 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0); 158 159 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0); 160 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, 161 fd, 0) == MAP_FAILED); 162 ATF_REQUIRE(errno == EACCES); 163 164 /* Make sure we can still map privately r/w or shared r/o. */ 165 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); 166 ATF_REQUIRE(paddr != MAP_FAILED); 167 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0); 168 ATF_REQUIRE(raddr != MAP_FAILED); 169 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0); 170 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0); 171 172 close(fd); 173 } 174 175 static int 176 memfd_truncate_test(int initial_size, int dest_size, int seals) 177 { 178 int err, fd; 179 180 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 181 ATF_REQUIRE(ftruncate(fd, initial_size) == 0); 182 183 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, seals) == 0); 184 185 err = ftruncate(fd, dest_size); 186 if (err != 0) 187 err = errno; 188 close(fd); 189 return (err); 190 } 191 192 ATF_TC_WITHOUT_HEAD(truncate_seals); 193 ATF_TC_BODY(truncate_seals, tc) 194 { 195 196 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW) == EPERM); 197 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_SHRINK) == EPERM); 198 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW) == 0); 199 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_SHRINK) == 0); 200 201 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW | F_SEAL_SHRINK) == 202 EPERM); 203 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW | F_SEAL_SHRINK) == 204 EPERM); 205 ATF_REQUIRE(memfd_truncate_test(4, 4, F_SEAL_GROW | F_SEAL_SHRINK) == 206 0); 207 } 208 209 ATF_TC_WITHOUT_HEAD(get_seals); 210 ATF_TC_BODY(get_seals, tc) 211 { 212 int fd; 213 int seals; 214 215 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 216 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0); 217 218 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0); 219 seals = fcntl(fd, F_GET_SEALS); 220 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); 221 222 close(fd); 223 } 224 225 ATF_TC_WITHOUT_HEAD(dup_seals); 226 ATF_TC_BODY(dup_seals, tc) 227 { 228 char buf[8]; 229 int fd, fdx; 230 int seals; 231 232 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 233 ATF_REQUIRE((fdx = dup(fd)) != -1); 234 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0); 235 236 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0); 237 seals = fcntl(fd, F_GET_SEALS); 238 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); 239 240 seals = fcntl(fdx, F_GET_SEALS); 241 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); 242 243 /* Make sure the seal's actually being applied at the inode level */ 244 ATF_REQUIRE(write(fdx, buf, sizeof(buf)) == -1); 245 ATF_REQUIRE(errno == EPERM); 246 247 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, 248 fdx, 0) == MAP_FAILED); 249 ATF_REQUIRE(errno == EACCES); 250 251 close(fd); 252 close(fdx); 253 } 254 255 ATF_TC_WITHOUT_HEAD(immutable_seals); 256 ATF_TC_BODY(immutable_seals, tc) 257 { 258 int fd; 259 260 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 261 262 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL) == 0); 263 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1); 264 ATF_REQUIRE_MSG(errno == EPERM, 265 "Added unique grow seal after restricting seals"); 266 267 close(fd); 268 269 /* 270 * Also check that adding a seal that already exists really doesn't 271 * do anything once we're sealed. 272 */ 273 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 274 275 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SEAL) == 0); 276 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1); 277 ATF_REQUIRE_MSG(errno == EPERM, 278 "Added duplicate grow seal after restricting seals"); 279 close(fd); 280 } 281 282 ATF_TP_ADD_TCS(tp) 283 { 284 285 ATF_TP_ADD_TC(tp, basic); 286 ATF_TP_ADD_TC(tp, cloexec); 287 ATF_TP_ADD_TC(tp, disallowed_sealing); 288 ATF_TP_ADD_TC(tp, write_seal); 289 ATF_TP_ADD_TC(tp, mmap_write_seal); 290 ATF_TP_ADD_TC(tp, truncate_seals); 291 ATF_TP_ADD_TC(tp, get_seals); 292 ATF_TP_ADD_TC(tp, dup_seals); 293 ATF_TP_ADD_TC(tp, immutable_seals); 294 return (atf_no_error()); 295 } 296