1 /*- 2 * Copyright (c) 2008-2009 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 /* 30 * Test routines to make sure a variety of system calls are or are not 31 * available in capability mode. The goal is not to see if they work, just 32 * whether or not they return the expected ECAPMODE. 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/capability.h> 40 #include <sys/mman.h> 41 #include <sys/mount.h> 42 #include <sys/poll.h> 43 #include <sys/socket.h> 44 #include <sys/stat.h> 45 #include <sys/wait.h> 46 47 #include <machine/sysarch.h> 48 #include <netinet/in.h> 49 50 #include <err.h> 51 #include <errno.h> 52 #include <fcntl.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 57 /* Need to check machine-dependent sysarch(). */ 58 #define ARCH_IS(s) (!strncmp(s, MACHINE, sizeof(s) + 1)) 59 60 #include "cap_test.h" 61 62 void 63 test_capmode(void) 64 { 65 struct sockaddr_in sin; 66 struct statfs statfs; 67 struct stat sb; 68 ssize_t len; 69 long sysarch_arg = 0; 70 int fd, fd_close, fd_dir, fd_file, fd_socket, fd2[2], ret; 71 pid_t pid, wpid; 72 char ch; 73 74 fd_file = open("/tmp/cap_test_syscalls", O_RDWR|O_CREAT, 0644); 75 if (fd_file < 0) 76 err(-1, "test_syscalls:prep: open cap_test_syscalls"); 77 78 fd_close = open("/dev/null", O_RDWR); 79 if (fd_close < 0) 80 err(-1, "test_syscalls:prep: open /dev/null"); 81 82 fd_dir = open("/tmp", O_RDONLY); 83 if (fd_dir < 0) 84 err(-1, "test_syscalls:prep: open /tmp"); 85 86 fd_socket = socket(PF_INET, SOCK_DGRAM, 0); 87 if (fd_socket < 0) 88 err(-1, "test_syscalls:prep: socket"); 89 90 if (cap_enter() < 0) 91 err(-1, "test_syscalls:prep: cap_enter"); 92 93 94 bzero(&sin, sizeof(sin)); 95 sin.sin_len = sizeof(sin); 96 sin.sin_family = AF_INET; 97 98 /* 99 * Here begin the tests, sorted roughly alphabetically by system call 100 * name. 101 */ 102 fd = accept(fd_socket, NULL, NULL); 103 if (fd < 0) { 104 if (errno == ECAPMODE) 105 warnx("test_syscalls:accept"); 106 } else { 107 warnx("test_syscalls:accept succeeded"); 108 close(fd); 109 } 110 111 if (access("/tmp/cap_test_syscalls_access", F_OK) < 0) { 112 if (errno != ECAPMODE) 113 warn("test_syscalls:access"); 114 } else 115 warnx("test_syscalls:access succeeded"); 116 117 if (acct("/tmp/cap_test_syscalls_acct") < 0) { 118 if (errno != ECAPMODE) 119 warn("test_syscalls:acct"); 120 } else 121 warnx("test_syscalls:acct succeeded"); 122 123 if (bind(PF_INET, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 124 if (errno != ECAPMODE) 125 warn("test_syscall:bind"); 126 } else 127 warnx("test_syscall:bind succeeded"); 128 129 if (chdir("/tmp/cap_test_syscalls_chdir") < 0) { 130 if (errno != ECAPMODE) 131 warn("test_syscalls:chdir"); 132 } else 133 warnx("test_syscalls:chdir succeeded"); 134 135 if (chflags("/tmp/cap_test_syscalls_chflags", UF_NODUMP) < 0) { 136 if (errno != ECAPMODE) 137 warn("test_syscalls:chflags"); 138 } else 139 warnx("test_syscalls:chflags succeeded"); 140 141 if (chmod("/tmp/cap_test_syscalls_chmod", 0644) < 0) { 142 if (errno != ECAPMODE) 143 warn("test_syscalls:chmod"); 144 } else 145 warnx("test_syscalls:chmod succeeded"); 146 147 if (chown("/tmp/cap_test_syscalls_chown", -1, -1) < 0) { 148 if (errno != ECAPMODE) 149 warn("test_syscalls:chown"); 150 } else 151 warnx("test_syscalls:chown succeeded"); 152 153 if (chroot("/tmp/cap_test_syscalls_chroot") < 0) { 154 if (errno != ECAPMODE) 155 warn("test_syscalls:chroot"); 156 } else 157 warnx("test_syscalls:chroot succeeded"); 158 159 if (close(fd_close)) { 160 if (errno == ECAPMODE) 161 warnx("test_syscalls:close"); 162 else 163 warn("test_syscalls:close"); 164 } 165 166 if (connect(PF_INET, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 167 if (errno != ECAPMODE) 168 warn("test_syscall:connect"); 169 } else 170 warnx("test_syscall:connect succeeded"); 171 172 fd = creat("/tmp/cap_test_syscalls_creat", 0644); 173 if (fd >= 0) { 174 warnx("test_syscalls:creat succeeded"); 175 close(fd); 176 } else if (errno != ECAPMODE) 177 warn("test_syscalls:creat"); 178 179 fd = dup(fd_file); 180 if (fd < 0) { 181 if (errno == ECAPMODE) 182 warnx("test_syscalls:dup"); 183 } else 184 close(fd); 185 186 if (fchdir(fd_dir) < 0) { 187 if (errno != ECAPMODE) 188 warn("test_syscall:fchdir"); 189 } else 190 warnx("test_syscalls:fchdir succeeded"); 191 192 if (fchflags(fd_file, UF_NODUMP) < 0) { 193 if (errno == ECAPMODE) 194 warnx("test_syscall:fchflags"); 195 } 196 197 pid = fork(); 198 if (pid >= 0) { 199 if (pid == 0) { 200 exit(0); 201 } else if (pid > 0) { 202 wpid = waitpid(pid, NULL, 0); 203 if (wpid < 0) { 204 if (errno != ECAPMODE) 205 warn("test_syscalls:waitpid"); 206 } else 207 warnx("test_syscalls:waitpid succeeded"); 208 } 209 } else 210 warn("test_syscalls:fork"); 211 212 if (fstat(fd_file, &sb) < 0) { 213 if (errno == ECAPMODE) 214 warnx("test_syscalls:fstat"); 215 } 216 217 /* 218 * getegid() can't return an error but check for it anyway. 219 */ 220 errno = 0; 221 (void)getegid(); 222 if (errno == ECAPMODE) 223 warnx("test_syscalls:getegid"); 224 225 /* 226 * geteuid() can't return an error but check for it anyway. 227 */ 228 errno = 0; 229 geteuid(); 230 if (errno == ECAPMODE) 231 warnx("test_syscalls:geteuid"); 232 233 if (getfsstat(&statfs, sizeof(statfs), MNT_NOWAIT) < 0) { 234 if (errno != ECAPMODE) 235 warn("test_syscalls:getfsstat"); 236 } else 237 warnx("test_syscalls:getfsstat succeeded"); 238 239 /* 240 * getgid() can't return an error but check for it anyway. 241 */ 242 errno = 0; 243 getgid(); 244 if (errno == ECAPMODE) 245 warnx("test_syscalls:getgid"); 246 247 if (getpeername(fd_socket, NULL, NULL) < 0) { 248 if (errno == ECAPMODE) 249 warnx("test_syscalls:getpeername"); 250 } 251 252 if (getlogin() == NULL) 253 warn("test_sycalls:getlogin %d", errno); 254 255 /* 256 * getpid() can't return an error but check for it anyway. 257 */ 258 errno = 0; 259 (void)getpid(); 260 if (errno == ECAPMODE) 261 warnx("test_syscalls:getpid"); 262 263 /* 264 * getppid() can't return an error but check for it anyway. 265 */ 266 errno = 0; 267 (void)getppid(); 268 if (errno == ECAPMODE) 269 warnx("test_syscalls:getppid"); 270 271 if (getsockname(fd_socket, NULL, NULL) < 0) { 272 if (errno == ECAPMODE) 273 warnx("test_syscalls:getsockname"); 274 } 275 276 /* 277 * getuid() can't return an error but check for it anyway. 278 */ 279 errno = 0; 280 (void)getuid(); 281 if (errno == ECAPMODE) 282 warnx("test_syscalls:getuid"); 283 284 /* XXXRW: ktrace */ 285 286 if (link("/tmp/foo", "/tmp/bar") < 0) { 287 if (errno != ECAPMODE) 288 warn("test_syscalls:link"); 289 } else 290 warnx("test_syscalls:link succeeded"); 291 292 ret = lseek(fd_file, SEEK_SET, 0); 293 if (ret < 0) { 294 if (errno == ECAPMODE) 295 warnx("test_syscalls:lseek"); 296 else 297 warn("test_syscalls:lseek"); 298 } 299 300 if (lstat("/tmp/cap_test_syscalls_lstat", &sb) < 0) { 301 if (errno != ECAPMODE) 302 warn("test_syscalls:lstat"); 303 } else 304 warnx("test_syscalls:lstat succeeded"); 305 306 if (mknod("/tmp/test_syscalls_mknod", 06440, 0) < 0) { 307 if (errno != ECAPMODE) 308 warn("test_syscalls:mknod"); 309 } else 310 warnx("test_syscalls:mknod succeeded"); 311 312 /* 313 * mount() is a bit tricky but do our best. 314 */ 315 if (mount("procfs", "/not_mounted", 0, NULL) < 0) { 316 if (errno != ECAPMODE) 317 warn("test_syscalls:mount"); 318 } else 319 warnx("test_syscalls:mount succeeded"); 320 321 if (msync(&fd_file, 8192, MS_ASYNC) < 0) { 322 if (errno == ECAPMODE) 323 warnx("test_syscalls:msync"); 324 } 325 326 fd = open("/dev/null", O_RDWR); 327 if (fd >= 0) { 328 warnx("test_syscalls:open succeeded"); 329 close(fd); 330 } 331 332 if (pipe(fd2) == 0) { 333 close(fd2[0]); 334 close(fd2[1]); 335 } else if (errno == ECAPMODE) 336 warnx("test_syscalls:pipe"); 337 338 if (profil(NULL, 0, 0, 0) < 0) { 339 if (errno == ECAPMODE) 340 warnx("test_syscalls:profile"); 341 } 342 343 /* XXXRW: ptrace. */ 344 345 len = read(fd_file, &ch, sizeof(ch)); 346 if (len < 0 && errno == ECAPMODE) 347 warnx("test_syscalls:read"); 348 349 if (readlink("/tmp/cap_test_syscalls_readlink", NULL, 0) < 0) { 350 if (errno != ECAPMODE) 351 warn("test_syscalls:readlink"); 352 } else 353 warnx("test_syscalls:readlink succeeded"); 354 355 len = recvfrom(fd_socket, NULL, 0, 0, NULL, NULL); 356 if (len < 0 && errno == ECAPMODE) 357 warnx("test_syscalls:recvfrom"); 358 359 len = recvmsg(fd_socket, NULL, 0); 360 if (len < 0 && errno == ECAPMODE) 361 warnx("test_syscalls:recvmsg"); 362 363 if (revoke("/tmp/cap_test_syscalls_revoke") < 0) { 364 if (errno != ECAPMODE) 365 warn("test_syscalls:revoke"); 366 } else 367 warnx("test_syscalls:revoke succeeded"); 368 369 len = sendmsg(fd_socket, NULL, 0); 370 if (len < 0 && errno == ECAPMODE) 371 warnx("test_syscalls:sendmsg"); 372 373 len = sendto(fd_socket, NULL, 0, 0, NULL, 0); 374 if (len < 0 && errno == ECAPMODE) 375 warn("test_syscalls:sendto(NULL)"); 376 377 if (setuid(getuid()) < 0) { 378 if (errno == ECAPMODE) 379 warnx("test_syscalls:setuid"); 380 } 381 382 if (stat("/tmp/cap_test_syscalls_stat", &sb) < 0) { 383 if (errno != ECAPMODE) 384 warn("test_syscalls:stat"); 385 } else 386 warnx("test_syscalls:stat succeeded"); 387 388 if (symlink("/tmp/cap_test_syscalls_symlink_from", 389 "/tmp/cap_test_syscalls_symlink_to") < 0) { 390 if (errno != ECAPMODE) 391 warn("test_syscalls:symlink"); 392 } else 393 warnx("test_syscalls:symlink succeeded"); 394 395 /* sysarch() is, by definition, architecture-dependent */ 396 if (ARCH_IS("i386") || ARCH_IS("amd64")) { 397 if (sysarch(I386_SET_IOPERM, &sysarch_arg) != -1) 398 warnx("test_syscalls:sysarch succeeded"); 399 else if (errno != ECAPMODE) 400 warn("test_syscalls:sysarch errno != ECAPMODE"); 401 402 /* XXXJA: write a test for arm */ 403 } else { 404 warnx("test_syscalls:no sysarch() test for architecture '%s'", MACHINE); 405 } 406 407 /* XXXRW: No error return from sync(2) to test. */ 408 409 if (unlink("/tmp/cap_test_syscalls_unlink") < 0) { 410 if (errno != ECAPMODE) 411 warn("test_syscalls:unlink"); 412 } else 413 warnx("test_syscalls:unlink succeeded"); 414 415 if (unmount("/not_mounted", 0) < 0) { 416 if (errno != ECAPMODE) 417 warn("test_syscalls:unmount"); 418 } else 419 warnx("test_syscalls:unmount succeeded"); 420 421 len = write(fd_file, &ch, sizeof(ch)); 422 if (len < 0 && errno == ECAPMODE) 423 warnx("test_syscalls:write"); 424 425 exit(0); 426 } 427