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 #include <sys/fcntl.h> 30 #include <sys/mman.h> 31 #include <sys/stat.h> 32 33 #include <atf-c.h> 34 #include <errno.h> 35 #include <unistd.h> 36 37 ATF_TC_WITHOUT_HEAD(basic); 38 ATF_TC_BODY(basic, tc) 39 { 40 struct stat sb; 41 int fd; 42 char buf[8]; 43 44 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1); 45 46 /* write(2) should grow us out automatically. */ 47 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf)); 48 ATF_REQUIRE(fstat(fd, &sb) == 0); 49 ATF_REQUIRE(sb.st_size == sizeof(buf)); 50 51 /* ftruncate(2) must succeed without seals */ 52 ATF_REQUIRE(ftruncate(fd, 2 * (sizeof(buf) - 1)) == 0); 53 54 /* write(2) again must not be limited by ftruncate(2) size. */ 55 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf)); 56 57 /* Sanity check. */ 58 ATF_REQUIRE(fstat(fd, &sb) == 0); 59 ATF_REQUIRE(sb.st_size == 2 * sizeof(buf)); 60 61 close(fd); 62 } 63 64 ATF_TC_WITHOUT_HEAD(cloexec); 65 ATF_TC_BODY(cloexec, tc) 66 { 67 int fd_nocl, fd_cl; 68 69 ATF_REQUIRE((fd_nocl = memfd_create("...", 0)) != -1); 70 ATF_REQUIRE((fd_cl = memfd_create("...", MFD_CLOEXEC)) != -1); 71 72 ATF_REQUIRE((fcntl(fd_nocl, F_GETFD) & FD_CLOEXEC) == 0); 73 ATF_REQUIRE((fcntl(fd_cl, F_GETFD) & FD_CLOEXEC) != 0); 74 75 close(fd_nocl); 76 close(fd_cl); 77 } 78 79 ATF_TC_WITHOUT_HEAD(disallowed_sealing); 80 ATF_TC_BODY(disallowed_sealing, tc) 81 { 82 int fd; 83 84 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1); 85 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == F_SEAL_SEAL); 86 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); 87 ATF_REQUIRE(errno == EPERM); 88 89 close(fd); 90 } 91 92 #define BUF_SIZE 1024 93 94 ATF_TC_WITHOUT_HEAD(write_seal); 95 ATF_TC_BODY(write_seal, tc) 96 { 97 int fd; 98 char *addr, buf[BUF_SIZE]; 99 100 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 101 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0); 102 103 /* Write once, then we'll seal it and try again */ 104 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == BUF_SIZE); 105 ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0); 106 107 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); 108 ATF_REQUIRE(addr != MAP_FAILED); 109 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0); 110 111 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0); 112 113 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == -1); 114 ATF_REQUIRE(errno == EPERM); 115 116 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, 117 fd, 0) == MAP_FAILED); 118 ATF_REQUIRE(errno == EACCES); 119 120 close(fd); 121 } 122 123 ATF_TC_WITHOUT_HEAD(mmap_write_seal); 124 ATF_TC_BODY(mmap_write_seal, tc) 125 { 126 int fd; 127 char *addr, *paddr, *raddr; 128 129 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 130 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0); 131 132 /* Map it, both shared and privately */ 133 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0); 134 ATF_REQUIRE(addr != MAP_FAILED); 135 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); 136 ATF_REQUIRE(paddr != MAP_FAILED); 137 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0); 138 ATF_REQUIRE(raddr != MAP_FAILED); 139 140 /* Now try to seal it before unmapping */ 141 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); 142 ATF_REQUIRE(errno == EBUSY); 143 144 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0); 145 146 /* 147 * This should fail, because raddr still exists and it was spawned from 148 * a r/w fd. 149 */ 150 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); 151 ATF_REQUIRE(errno == EBUSY); 152 153 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0); 154 /* This one should succeed; only the private mapping remains. */ 155 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0); 156 157 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0); 158 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, 159 fd, 0) == MAP_FAILED); 160 ATF_REQUIRE(errno == EACCES); 161 162 /* Make sure we can still map privately r/w or shared r/o. */ 163 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); 164 ATF_REQUIRE(paddr != MAP_FAILED); 165 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0); 166 ATF_REQUIRE(raddr != MAP_FAILED); 167 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0); 168 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0); 169 170 close(fd); 171 } 172 173 static int 174 memfd_truncate_test(int initial_size, int dest_size, int seals) 175 { 176 int err, fd; 177 178 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 179 ATF_REQUIRE(ftruncate(fd, initial_size) == 0); 180 181 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, seals) == 0); 182 183 err = ftruncate(fd, dest_size); 184 if (err != 0) 185 err = errno; 186 close(fd); 187 return (err); 188 } 189 190 ATF_TC_WITHOUT_HEAD(truncate_seals); 191 ATF_TC_BODY(truncate_seals, tc) 192 { 193 194 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW) == EPERM); 195 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_SHRINK) == EPERM); 196 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW) == 0); 197 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_SHRINK) == 0); 198 199 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW | F_SEAL_SHRINK) == 200 EPERM); 201 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW | F_SEAL_SHRINK) == 202 EPERM); 203 ATF_REQUIRE(memfd_truncate_test(4, 4, F_SEAL_GROW | F_SEAL_SHRINK) == 204 0); 205 } 206 207 ATF_TC_WITHOUT_HEAD(get_seals); 208 ATF_TC_BODY(get_seals, tc) 209 { 210 int fd; 211 int seals; 212 213 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 214 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0); 215 216 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0); 217 seals = fcntl(fd, F_GET_SEALS); 218 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); 219 220 close(fd); 221 } 222 223 ATF_TC_WITHOUT_HEAD(dup_seals); 224 ATF_TC_BODY(dup_seals, tc) 225 { 226 char buf[8]; 227 int fd, fdx; 228 int seals; 229 230 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 231 ATF_REQUIRE((fdx = dup(fd)) != -1); 232 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0); 233 234 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0); 235 seals = fcntl(fd, F_GET_SEALS); 236 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); 237 238 seals = fcntl(fdx, F_GET_SEALS); 239 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); 240 241 /* Make sure the seal's actually being applied at the inode level */ 242 ATF_REQUIRE(write(fdx, buf, sizeof(buf)) == -1); 243 ATF_REQUIRE(errno == EPERM); 244 245 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, 246 fdx, 0) == MAP_FAILED); 247 ATF_REQUIRE(errno == EACCES); 248 249 close(fd); 250 close(fdx); 251 } 252 253 ATF_TC_WITHOUT_HEAD(immutable_seals); 254 ATF_TC_BODY(immutable_seals, tc) 255 { 256 int fd; 257 258 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 259 260 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL) == 0); 261 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1); 262 ATF_REQUIRE_MSG(errno == EPERM, 263 "Added unique grow seal after restricting seals"); 264 265 close(fd); 266 267 /* 268 * Also check that adding a seal that already exists really doesn't 269 * do anything once we're sealed. 270 */ 271 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); 272 273 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SEAL) == 0); 274 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1); 275 ATF_REQUIRE_MSG(errno == EPERM, 276 "Added duplicate grow seal after restricting seals"); 277 close(fd); 278 } 279 280 ATF_TP_ADD_TCS(tp) 281 { 282 283 ATF_TP_ADD_TC(tp, basic); 284 ATF_TP_ADD_TC(tp, cloexec); 285 ATF_TP_ADD_TC(tp, disallowed_sealing); 286 ATF_TP_ADD_TC(tp, write_seal); 287 ATF_TP_ADD_TC(tp, mmap_write_seal); 288 ATF_TP_ADD_TC(tp, truncate_seals); 289 ATF_TP_ADD_TC(tp, get_seals); 290 ATF_TP_ADD_TC(tp, dup_seals); 291 ATF_TP_ADD_TC(tp, immutable_seals); 292 return (atf_no_error()); 293 } 294