cap_test_capabilities.c revision 224653
1/*- 2 * Copyright (c) 2009-2011 Robert N. M. Watson 3 * Copyright (c) 2011 Jonathan Anderson 4 * All rights reserved. 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/* 29 * Test whether various operations on capabilities are properly masked for 30 * various object types. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/tools/regression/security/cap_test/cap_test_capabilities.c 224653 2011-08-04 17:17:57Z jonathan $"); 35 36#include <sys/param.h> 37#include <sys/capability.h> 38#include <sys/errno.h> 39#include <sys/mman.h> 40#include <sys/mount.h> 41#include <sys/stat.h> 42 43#include <err.h> 44#include <fcntl.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <unistd.h> 48 49#include "cap_test.h" 50 51#define SYSCALL_FAIL(syscall, message) \ 52 FAIL("%s:\t%s (rights 0x%jx)", #syscall, message, rights) 53 54/* 55 * Ensure that, if the capability had enough rights for the system call to 56 * pass, then it did. Otherwise, ensure that the errno is ENOTCAPABLE; 57 * capability restrictions should kick in before any other error logic. 58 */ 59#define CHECK_RESULT(syscall, rights_needed, succeeded) do { \ 60 if ((rights & (rights_needed)) == (rights_needed)) { \ 61 if (!(succeeded)) \ 62 SYSCALL_FAIL(syscall, "failed"); \ 63 } else { \ 64 if (succeeded) \ 65 FAILX("%s:\tsucceeded when it shouldn't have" \ 66 " (rights 0x%jx)", #syscall, rights); \ 67 else if (errno != ENOTCAPABLE) \ 68 SYSCALL_FAIL(syscall, "errno != ENOTCAPABLE"); \ 69 } \ 70} while (0) 71 72/* 73 * As above, but for the special mmap() case: unmap after successful mmap(). 74 */ 75#define CHECK_MMAP_RESULT(rights_needed) do { \ 76 if ((rights & (rights_needed)) == (rights_needed)) { \ 77 if (p == MAP_FAILED) \ 78 SYSCALL_FAIL(mmap, "failed"); \ 79 else \ 80 (void)munmap(p, getpagesize()); \ 81 } else { \ 82 if (p != MAP_FAILED) { \ 83 FAILX("%s:\tsucceeded when it shouldn't have" \ 84 " (rights 0x%jx)", "mmap", rights); \ 85 (void)munmap(p, getpagesize()); \ 86 } else if (errno != ENOTCAPABLE) \ 87 SYSCALL_FAIL(syscall, "errno != ENOTCAPABLE"); \ 88 } \ 89} while (0) 90 91/* 92 * Given a file descriptor, create a capability with specific rights and 93 * make sure only those rights work. 94*/ 95static int 96try_file_ops(int fd, cap_rights_t rights) 97{ 98 struct stat sb; 99 struct statfs sf; 100 int fd_cap, fd_capcap; 101 ssize_t ssize, ssize2; 102 off_t off; 103 void *p; 104 char ch; 105 int ret; 106 int success = PASSED; 107 108 REQUIRE(fd_cap = cap_new(fd, rights)); 109 REQUIRE(fd_capcap = cap_new(fd_cap, rights)); 110 CHECK(fd_capcap != fd_cap); 111 112 ssize = read(fd_cap, &ch, sizeof(ch)); 113 CHECK_RESULT(read, CAP_READ | CAP_SEEK, ssize >= 0); 114 115 ssize = pread(fd_cap, &ch, sizeof(ch), 0); 116 ssize2 = pread(fd_cap, &ch, sizeof(ch), 0); 117 CHECK_RESULT(pread, CAP_READ, ssize >= 0); 118 CHECK(ssize == ssize2); 119 120 ssize = write(fd_cap, &ch, sizeof(ch)); 121 CHECK_RESULT(write, CAP_WRITE | CAP_SEEK, ssize >= 0); 122 123 ssize = pwrite(fd_cap, &ch, sizeof(ch), 0); 124 CHECK_RESULT(pwrite, CAP_WRITE, ssize >= 0); 125 126 off = lseek(fd_cap, 0, SEEK_SET); 127 CHECK_RESULT(lseek, CAP_SEEK, off >= 0); 128 129 ret = fchflags(fd_cap, UF_NODUMP); 130 CHECK_RESULT(fchflags, CAP_FCHFLAGS, ret == 0); 131 132 ret = fstat(fd_cap, &sb); 133 CHECK_RESULT(fstat, CAP_FSTAT, ret == 0); 134 135 p = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd_cap, 0); 136 CHECK_MMAP_RESULT(CAP_MMAP | CAP_READ); 137 138 p = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd_cap, 0); 139 CHECK_MMAP_RESULT(CAP_MMAP | CAP_WRITE); 140 141 p = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd_cap, 0); 142 CHECK_MMAP_RESULT(CAP_MMAP | CAP_MAPEXEC); 143 144 p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, 145 fd_cap, 0); 146 CHECK_MMAP_RESULT(CAP_MMAP | CAP_READ | CAP_WRITE); 147 148 p = mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_SHARED, 149 fd_cap, 0); 150 CHECK_MMAP_RESULT(CAP_MMAP | CAP_READ | CAP_MAPEXEC); 151 152 p = mmap(NULL, getpagesize(), PROT_EXEC | PROT_WRITE, MAP_SHARED, 153 fd_cap, 0); 154 CHECK_MMAP_RESULT(CAP_MMAP | CAP_MAPEXEC | CAP_WRITE); 155 156 p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, 157 MAP_SHARED, fd_cap, 0); 158 CHECK_MMAP_RESULT(CAP_MMAP | CAP_READ | CAP_WRITE | CAP_MAPEXEC); 159 160 ret = fsync(fd_cap); 161 CHECK_RESULT(fsync, CAP_FSYNC, ret == 0); 162 163 ret = fchown(fd_cap, -1, -1); 164 CHECK_RESULT(fchown, CAP_FCHOWN, ret == 0); 165 166 ret = fchmod(fd_cap, 0644); 167 CHECK_RESULT(fchmod, CAP_FCHMOD, ret == 0); 168 169 /* XXX flock */ 170 171 ret = ftruncate(fd_cap, 0); 172 CHECK_RESULT(ftruncate, CAP_FTRUNCATE, ret == 0); 173 174 ret = fstatfs(fd_cap, &sf); 175 CHECK_RESULT(fstatfs, CAP_FSTATFS, ret == 0); 176 177 ret = fpathconf(fd_cap, _PC_NAME_MAX); 178 CHECK_RESULT(fpathconf, CAP_FPATHCONF, ret >= 0); 179 180 ret = futimes(fd_cap, NULL); 181 CHECK_RESULT(futimes, CAP_FUTIMES, ret == 0); 182 183 /* XXX select / poll / kqueue */ 184 185 close (fd_cap); 186 return (success); 187} 188 189#define TRY(fd, rights) \ 190do { \ 191 if (success == PASSED) \ 192 success = try_file_ops(fd, rights); \ 193 else \ 194 /* We've already failed, but try the test anyway. */ \ 195 try_file_ops(fd, rights); \ 196} while (0) 197 198int 199test_capabilities(void) 200{ 201 int fd; 202 int success = PASSED; 203 204 fd = open("/tmp/cap_test", O_RDWR | O_CREAT, 0644); 205 if (fd < 0) 206 err(-1, "open"); 207 208 if (cap_enter() < 0) 209 err(-1, "cap_enter"); 210 211 /* XXX: Really want to try all combinations. */ 212 TRY(fd, CAP_READ); 213 TRY(fd, CAP_READ | CAP_SEEK); 214 TRY(fd, CAP_WRITE); 215 TRY(fd, CAP_WRITE | CAP_SEEK); 216 TRY(fd, CAP_READ | CAP_WRITE); 217 TRY(fd, CAP_READ | CAP_WRITE | CAP_SEEK); 218 TRY(fd, CAP_SEEK); 219 TRY(fd, CAP_FCHFLAGS); 220 TRY(fd, CAP_IOCTL); 221 TRY(fd, CAP_FSTAT); 222 TRY(fd, CAP_MMAP); 223 TRY(fd, CAP_MMAP | CAP_READ); 224 TRY(fd, CAP_MMAP | CAP_WRITE); 225 TRY(fd, CAP_MMAP | CAP_MAPEXEC); 226 TRY(fd, CAP_MMAP | CAP_READ | CAP_WRITE); 227 TRY(fd, CAP_MMAP | CAP_READ | CAP_MAPEXEC); 228 TRY(fd, CAP_MMAP | CAP_MAPEXEC | CAP_WRITE); 229 TRY(fd, CAP_MMAP | CAP_READ | CAP_WRITE | CAP_MAPEXEC); 230 TRY(fd, CAP_FCNTL); 231 TRY(fd, CAP_EVENT); 232 TRY(fd, CAP_KEVENT); 233 TRY(fd, CAP_FSYNC); 234 TRY(fd, CAP_FCHOWN); 235 TRY(fd, CAP_FCHMOD); 236 TRY(fd, CAP_FTRUNCATE); 237 TRY(fd, CAP_FLOCK); 238 TRY(fd, CAP_FSTATFS); 239 TRY(fd, CAP_FPATHCONF); 240 TRY(fd, CAP_FUTIMES); 241 TRY(fd, CAP_ACL_GET); 242 TRY(fd, CAP_ACL_SET); 243 TRY(fd, CAP_ACL_DELETE); 244 TRY(fd, CAP_ACL_CHECK); 245 TRY(fd, CAP_EXTATTR_GET); 246 TRY(fd, CAP_EXTATTR_SET); 247 TRY(fd, CAP_EXTATTR_DELETE); 248 TRY(fd, CAP_EXTATTR_LIST); 249 TRY(fd, CAP_MAC_GET); 250 TRY(fd, CAP_MAC_SET); 251 252 /* 253 * Socket-specific. 254 */ 255 TRY(fd, CAP_GETPEERNAME); 256 TRY(fd, CAP_GETSOCKNAME); 257 TRY(fd, CAP_ACCEPT); 258 259 return (success); 260} 261