1/*- 2 * Copyright (c) 2015 Nuxi, https://nuxi.nl/ 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: stable/11/sys/compat/cloudabi/cloudabi_fd.c 351142 2019-08-16 21:01:35Z kevans $"); 28 29#include <sys/param.h> 30#include <sys/capsicum.h> 31#include <sys/filedesc.h> 32#include <sys/proc.h> 33#include <sys/mman.h> 34#include <sys/socketvar.h> 35#include <sys/syscallsubr.h> 36#include <sys/sysproto.h> 37#include <sys/systm.h> 38#include <sys/unistd.h> 39#include <sys/vnode.h> 40 41#include <contrib/cloudabi/cloudabi_types_common.h> 42 43#include <compat/cloudabi/cloudabi_proto.h> 44#include <compat/cloudabi/cloudabi_util.h> 45 46/* Translation between CloudABI and Capsicum rights. */ 47#define RIGHTS_MAPPINGS \ 48 MAPPING(CLOUDABI_RIGHT_FD_DATASYNC, CAP_FSYNC) \ 49 MAPPING(CLOUDABI_RIGHT_FD_READ, CAP_READ) \ 50 MAPPING(CLOUDABI_RIGHT_FD_SEEK, CAP_SEEK) \ 51 MAPPING(CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS, CAP_FCNTL) \ 52 MAPPING(CLOUDABI_RIGHT_FD_SYNC, CAP_FSYNC) \ 53 MAPPING(CLOUDABI_RIGHT_FD_TELL, CAP_SEEK_TELL) \ 54 MAPPING(CLOUDABI_RIGHT_FD_WRITE, CAP_WRITE) \ 55 MAPPING(CLOUDABI_RIGHT_FILE_ADVISE) \ 56 MAPPING(CLOUDABI_RIGHT_FILE_ALLOCATE, CAP_WRITE) \ 57 MAPPING(CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY, CAP_MKDIRAT) \ 58 MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FILE, CAP_CREATE) \ 59 MAPPING(CLOUDABI_RIGHT_FILE_LINK_SOURCE, CAP_LINKAT_SOURCE) \ 60 MAPPING(CLOUDABI_RIGHT_FILE_LINK_TARGET, CAP_LINKAT_TARGET) \ 61 MAPPING(CLOUDABI_RIGHT_FILE_OPEN, CAP_LOOKUP) \ 62 MAPPING(CLOUDABI_RIGHT_FILE_READDIR, CAP_READ) \ 63 MAPPING(CLOUDABI_RIGHT_FILE_READLINK, CAP_LOOKUP) \ 64 MAPPING(CLOUDABI_RIGHT_FILE_RENAME_SOURCE, CAP_RENAMEAT_SOURCE) \ 65 MAPPING(CLOUDABI_RIGHT_FILE_RENAME_TARGET, CAP_RENAMEAT_TARGET) \ 66 MAPPING(CLOUDABI_RIGHT_FILE_STAT_FGET, CAP_FSTAT) \ 67 MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE, CAP_FTRUNCATE) \ 68 MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES, CAP_FUTIMES) \ 69 MAPPING(CLOUDABI_RIGHT_FILE_STAT_GET, CAP_FSTATAT) \ 70 MAPPING(CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES, CAP_FUTIMESAT) \ 71 MAPPING(CLOUDABI_RIGHT_FILE_SYMLINK, CAP_SYMLINKAT) \ 72 MAPPING(CLOUDABI_RIGHT_FILE_UNLINK, CAP_UNLINKAT) \ 73 MAPPING(CLOUDABI_RIGHT_MEM_MAP, CAP_MMAP) \ 74 MAPPING(CLOUDABI_RIGHT_MEM_MAP_EXEC, CAP_MMAP_X) \ 75 MAPPING(CLOUDABI_RIGHT_POLL_FD_READWRITE, CAP_EVENT) \ 76 MAPPING(CLOUDABI_RIGHT_POLL_PROC_TERMINATE, CAP_EVENT) \ 77 MAPPING(CLOUDABI_RIGHT_PROC_EXEC, CAP_FEXECVE) \ 78 MAPPING(CLOUDABI_RIGHT_SOCK_SHUTDOWN, CAP_SHUTDOWN) \ 79 80int 81cloudabi_sys_fd_close(struct thread *td, struct cloudabi_sys_fd_close_args *uap) 82{ 83 84 return (kern_close(td, uap->fd)); 85} 86 87int 88cloudabi_sys_fd_create1(struct thread *td, 89 struct cloudabi_sys_fd_create1_args *uap) 90{ 91 struct filecaps fcaps = {}; 92 93 switch (uap->type) { 94 case CLOUDABI_FILETYPE_SHARED_MEMORY: 95 cap_rights_init(&fcaps.fc_rights, CAP_FSTAT, CAP_FTRUNCATE, 96 CAP_MMAP_RWX); 97 return (kern_shm_open(td, SHM_ANON, O_RDWR | O_CLOEXEC, 0, 98 &fcaps)); 99 default: 100 return (EINVAL); 101 } 102} 103 104int 105cloudabi_sys_fd_create2(struct thread *td, 106 struct cloudabi_sys_fd_create2_args *uap) 107{ 108 int fds[2]; 109 int error, type; 110 111 switch (uap->type) { 112 case CLOUDABI_FILETYPE_SOCKET_DGRAM: 113 type = SOCK_DGRAM; 114 break; 115 case CLOUDABI_FILETYPE_SOCKET_STREAM: 116 type = SOCK_STREAM; 117 break; 118 default: 119 return (EINVAL); 120 } 121 122 error = kern_socketpair(td, AF_UNIX, type, 0, fds); 123 if (error == 0) { 124 td->td_retval[0] = fds[0]; 125 td->td_retval[1] = fds[1]; 126 } 127 return (0); 128} 129 130int 131cloudabi_sys_fd_datasync(struct thread *td, 132 struct cloudabi_sys_fd_datasync_args *uap) 133{ 134 135 return (kern_fsync(td, uap->fd, false)); 136} 137 138int 139cloudabi_sys_fd_dup(struct thread *td, struct cloudabi_sys_fd_dup_args *uap) 140{ 141 142 return (kern_dup(td, FDDUP_NORMAL, 0, uap->from, 0)); 143} 144 145int 146cloudabi_sys_fd_replace(struct thread *td, 147 struct cloudabi_sys_fd_replace_args *uap) 148{ 149 int error; 150 151 /* 152 * CloudABI's equivalent to dup2(). CloudABI processes should 153 * not depend on hardcoded file descriptor layouts, but simply 154 * use the file descriptor numbers that are allocated by the 155 * kernel. Duplicating file descriptors to arbitrary numbers 156 * should not be done. 157 * 158 * Invoke kern_dup() with FDDUP_MUSTREPLACE, so that we return 159 * EBADF when duplicating to a nonexistent file descriptor. Also 160 * clear the return value, as this system call yields no return 161 * value. 162 */ 163 error = kern_dup(td, FDDUP_MUSTREPLACE, 0, uap->from, uap->to); 164 td->td_retval[0] = 0; 165 return (error); 166} 167 168int 169cloudabi_sys_fd_seek(struct thread *td, struct cloudabi_sys_fd_seek_args *uap) 170{ 171 int whence; 172 173 switch (uap->whence) { 174 case CLOUDABI_WHENCE_CUR: 175 whence = SEEK_CUR; 176 break; 177 case CLOUDABI_WHENCE_END: 178 whence = SEEK_END; 179 break; 180 case CLOUDABI_WHENCE_SET: 181 whence = SEEK_SET; 182 break; 183 default: 184 return (EINVAL); 185 } 186 187 return (kern_lseek(td, uap->fd, uap->offset, whence)); 188} 189 190/* Converts a file descriptor to a CloudABI file descriptor type. */ 191cloudabi_filetype_t 192cloudabi_convert_filetype(const struct file *fp) 193{ 194 struct socket *so; 195 struct vnode *vp; 196 197 switch (fp->f_type) { 198 case DTYPE_FIFO: 199 return (CLOUDABI_FILETYPE_SOCKET_STREAM); 200 case DTYPE_PIPE: 201 return (CLOUDABI_FILETYPE_SOCKET_STREAM); 202 case DTYPE_PROCDESC: 203 return (CLOUDABI_FILETYPE_PROCESS); 204 case DTYPE_SHM: 205 return (CLOUDABI_FILETYPE_SHARED_MEMORY); 206 case DTYPE_SOCKET: 207 so = fp->f_data; 208 switch (so->so_type) { 209 case SOCK_DGRAM: 210 return (CLOUDABI_FILETYPE_SOCKET_DGRAM); 211 case SOCK_STREAM: 212 return (CLOUDABI_FILETYPE_SOCKET_STREAM); 213 default: 214 return (CLOUDABI_FILETYPE_UNKNOWN); 215 } 216 case DTYPE_VNODE: 217 vp = fp->f_vnode; 218 switch (vp->v_type) { 219 case VBLK: 220 return (CLOUDABI_FILETYPE_BLOCK_DEVICE); 221 case VCHR: 222 return (CLOUDABI_FILETYPE_CHARACTER_DEVICE); 223 case VDIR: 224 return (CLOUDABI_FILETYPE_DIRECTORY); 225 case VFIFO: 226 return (CLOUDABI_FILETYPE_SOCKET_STREAM); 227 case VLNK: 228 return (CLOUDABI_FILETYPE_SYMBOLIC_LINK); 229 case VREG: 230 return (CLOUDABI_FILETYPE_REGULAR_FILE); 231 case VSOCK: 232 return (CLOUDABI_FILETYPE_SOCKET_STREAM); 233 default: 234 return (CLOUDABI_FILETYPE_UNKNOWN); 235 } 236 default: 237 return (CLOUDABI_FILETYPE_UNKNOWN); 238 } 239} 240 241/* Removes rights that conflict with the file descriptor type. */ 242void 243cloudabi_remove_conflicting_rights(cloudabi_filetype_t filetype, 244 cloudabi_rights_t *base, cloudabi_rights_t *inheriting) 245{ 246 247 /* 248 * CloudABI has a small number of additional rights bits to 249 * disambiguate between multiple purposes. Remove the bits that 250 * don't apply to the type of the file descriptor. 251 * 252 * As file descriptor access modes (O_ACCMODE) has been fully 253 * replaced by rights bits, CloudABI distinguishes between 254 * rights that apply to the file descriptor itself (base) versus 255 * rights of new file descriptors derived from them 256 * (inheriting). The code below approximates the pair by 257 * decomposing depending on the file descriptor type. 258 * 259 * We need to be somewhat accurate about which actions can 260 * actually be performed on the file descriptor, as functions 261 * like fcntl(fd, F_GETFL) are emulated on top of this. 262 */ 263 switch (filetype) { 264 case CLOUDABI_FILETYPE_DIRECTORY: 265 *base &= CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | 266 CLOUDABI_RIGHT_FD_SYNC | CLOUDABI_RIGHT_FILE_ADVISE | 267 CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY | 268 CLOUDABI_RIGHT_FILE_CREATE_FILE | 269 CLOUDABI_RIGHT_FILE_LINK_SOURCE | 270 CLOUDABI_RIGHT_FILE_LINK_TARGET | 271 CLOUDABI_RIGHT_FILE_OPEN | 272 CLOUDABI_RIGHT_FILE_READDIR | 273 CLOUDABI_RIGHT_FILE_READLINK | 274 CLOUDABI_RIGHT_FILE_RENAME_SOURCE | 275 CLOUDABI_RIGHT_FILE_RENAME_TARGET | 276 CLOUDABI_RIGHT_FILE_STAT_FGET | 277 CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES | 278 CLOUDABI_RIGHT_FILE_STAT_GET | 279 CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES | 280 CLOUDABI_RIGHT_FILE_SYMLINK | 281 CLOUDABI_RIGHT_FILE_UNLINK | 282 CLOUDABI_RIGHT_POLL_FD_READWRITE; 283 *inheriting &= CLOUDABI_RIGHT_FD_DATASYNC | 284 CLOUDABI_RIGHT_FD_READ | 285 CLOUDABI_RIGHT_FD_SEEK | 286 CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | 287 CLOUDABI_RIGHT_FD_SYNC | 288 CLOUDABI_RIGHT_FD_TELL | 289 CLOUDABI_RIGHT_FD_WRITE | 290 CLOUDABI_RIGHT_FILE_ADVISE | 291 CLOUDABI_RIGHT_FILE_ALLOCATE | 292 CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY | 293 CLOUDABI_RIGHT_FILE_CREATE_FILE | 294 CLOUDABI_RIGHT_FILE_LINK_SOURCE | 295 CLOUDABI_RIGHT_FILE_LINK_TARGET | 296 CLOUDABI_RIGHT_FILE_OPEN | 297 CLOUDABI_RIGHT_FILE_READDIR | 298 CLOUDABI_RIGHT_FILE_READLINK | 299 CLOUDABI_RIGHT_FILE_RENAME_SOURCE | 300 CLOUDABI_RIGHT_FILE_RENAME_TARGET | 301 CLOUDABI_RIGHT_FILE_STAT_FGET | 302 CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE | 303 CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES | 304 CLOUDABI_RIGHT_FILE_STAT_GET | 305 CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES | 306 CLOUDABI_RIGHT_FILE_SYMLINK | 307 CLOUDABI_RIGHT_FILE_UNLINK | 308 CLOUDABI_RIGHT_MEM_MAP | 309 CLOUDABI_RIGHT_MEM_MAP_EXEC | 310 CLOUDABI_RIGHT_POLL_FD_READWRITE | 311 CLOUDABI_RIGHT_PROC_EXEC; 312 break; 313 case CLOUDABI_FILETYPE_PROCESS: 314 *base &= ~(CLOUDABI_RIGHT_FILE_ADVISE | 315 CLOUDABI_RIGHT_POLL_FD_READWRITE); 316 *inheriting = 0; 317 break; 318 case CLOUDABI_FILETYPE_REGULAR_FILE: 319 *base &= CLOUDABI_RIGHT_FD_DATASYNC | 320 CLOUDABI_RIGHT_FD_READ | 321 CLOUDABI_RIGHT_FD_SEEK | 322 CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | 323 CLOUDABI_RIGHT_FD_SYNC | 324 CLOUDABI_RIGHT_FD_TELL | 325 CLOUDABI_RIGHT_FD_WRITE | 326 CLOUDABI_RIGHT_FILE_ADVISE | 327 CLOUDABI_RIGHT_FILE_ALLOCATE | 328 CLOUDABI_RIGHT_FILE_STAT_FGET | 329 CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE | 330 CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES | 331 CLOUDABI_RIGHT_MEM_MAP | 332 CLOUDABI_RIGHT_MEM_MAP_EXEC | 333 CLOUDABI_RIGHT_POLL_FD_READWRITE | 334 CLOUDABI_RIGHT_PROC_EXEC; 335 *inheriting = 0; 336 break; 337 case CLOUDABI_FILETYPE_SHARED_MEMORY: 338 *base &= ~(CLOUDABI_RIGHT_FD_SEEK | 339 CLOUDABI_RIGHT_FD_TELL | 340 CLOUDABI_RIGHT_FILE_ADVISE | 341 CLOUDABI_RIGHT_FILE_ALLOCATE | 342 CLOUDABI_RIGHT_FILE_READDIR); 343 *inheriting = 0; 344 break; 345 case CLOUDABI_FILETYPE_SOCKET_DGRAM: 346 case CLOUDABI_FILETYPE_SOCKET_STREAM: 347 *base &= CLOUDABI_RIGHT_FD_READ | 348 CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | 349 CLOUDABI_RIGHT_FD_WRITE | 350 CLOUDABI_RIGHT_FILE_STAT_FGET | 351 CLOUDABI_RIGHT_POLL_FD_READWRITE | 352 CLOUDABI_RIGHT_SOCK_SHUTDOWN; 353 break; 354 default: 355 *inheriting = 0; 356 break; 357 } 358} 359 360/* Converts FreeBSD's Capsicum rights to CloudABI's set of rights. */ 361static void 362convert_capabilities(const cap_rights_t *capabilities, 363 cloudabi_filetype_t filetype, cloudabi_rights_t *base, 364 cloudabi_rights_t *inheriting) 365{ 366 cloudabi_rights_t rights; 367 368 /* Convert FreeBSD bits to CloudABI bits. */ 369 rights = 0; 370#define MAPPING(cloudabi, ...) do { \ 371 if (cap_rights_is_set(capabilities, ##__VA_ARGS__)) \ 372 rights |= (cloudabi); \ 373} while (0); 374 RIGHTS_MAPPINGS 375#undef MAPPING 376 377 *base = rights; 378 *inheriting = rights; 379 cloudabi_remove_conflicting_rights(filetype, base, inheriting); 380} 381 382int 383cloudabi_sys_fd_stat_get(struct thread *td, 384 struct cloudabi_sys_fd_stat_get_args *uap) 385{ 386 cloudabi_fdstat_t fsb = {}; 387 struct filedesc *fdp; 388 struct file *fp; 389 seq_t seq; 390 cap_rights_t rights; 391 int error, oflags; 392 bool modified; 393 394 /* Obtain file descriptor properties. */ 395 fdp = td->td_proc->p_fd; 396 do { 397 error = fget_unlocked(fdp, uap->fd, cap_rights_init(&rights), 398 &fp, &seq); 399 if (error != 0) 400 return (error); 401 if (fp->f_ops == &badfileops) { 402 fdrop(fp, td); 403 return (EBADF); 404 } 405 406 rights = *cap_rights(fdp, uap->fd); 407 oflags = OFLAGS(fp->f_flag); 408 fsb.fs_filetype = cloudabi_convert_filetype(fp); 409 410 modified = fd_modified(fdp, uap->fd, seq); 411 fdrop(fp, td); 412 } while (modified); 413 414 /* Convert file descriptor flags. */ 415 if (oflags & O_APPEND) 416 fsb.fs_flags |= CLOUDABI_FDFLAG_APPEND; 417 if (oflags & O_NONBLOCK) 418 fsb.fs_flags |= CLOUDABI_FDFLAG_NONBLOCK; 419 if (oflags & O_SYNC) 420 fsb.fs_flags |= CLOUDABI_FDFLAG_SYNC; 421 422 /* Convert capabilities to CloudABI rights. */ 423 convert_capabilities(&rights, fsb.fs_filetype, 424 &fsb.fs_rights_base, &fsb.fs_rights_inheriting); 425 return (copyout(&fsb, (void *)uap->buf, sizeof(fsb))); 426} 427 428/* Converts CloudABI rights to a set of Capsicum capabilities. */ 429int 430cloudabi_convert_rights(cloudabi_rights_t in, cap_rights_t *out) 431{ 432 433 cap_rights_init(out); 434#define MAPPING(cloudabi, ...) do { \ 435 if (in & (cloudabi)) { \ 436 cap_rights_set(out, ##__VA_ARGS__); \ 437 in &= ~(cloudabi); \ 438 } \ 439} while (0); 440 RIGHTS_MAPPINGS 441#undef MAPPING 442 if (in != 0) 443 return (ENOTCAPABLE); 444 return (0); 445} 446 447int 448cloudabi_sys_fd_stat_put(struct thread *td, 449 struct cloudabi_sys_fd_stat_put_args *uap) 450{ 451 cloudabi_fdstat_t fsb; 452 cap_rights_t rights; 453 int error, oflags; 454 455 error = copyin(uap->buf, &fsb, sizeof(fsb)); 456 if (error != 0) 457 return (error); 458 459 if (uap->flags == CLOUDABI_FDSTAT_FLAGS) { 460 /* Convert flags. */ 461 oflags = 0; 462 if (fsb.fs_flags & CLOUDABI_FDFLAG_APPEND) 463 oflags |= O_APPEND; 464 if (fsb.fs_flags & CLOUDABI_FDFLAG_NONBLOCK) 465 oflags |= O_NONBLOCK; 466 if (fsb.fs_flags & (CLOUDABI_FDFLAG_SYNC | 467 CLOUDABI_FDFLAG_DSYNC | CLOUDABI_FDFLAG_RSYNC)) 468 oflags |= O_SYNC; 469 return (kern_fcntl(td, uap->fd, F_SETFL, oflags)); 470 } else if (uap->flags == CLOUDABI_FDSTAT_RIGHTS) { 471 /* Convert rights. */ 472 error = cloudabi_convert_rights( 473 fsb.fs_rights_base | fsb.fs_rights_inheriting, &rights); 474 if (error != 0) 475 return (error); 476 return (kern_cap_rights_limit(td, uap->fd, &rights)); 477 } 478 return (EINVAL); 479} 480 481int 482cloudabi_sys_fd_sync(struct thread *td, struct cloudabi_sys_fd_sync_args *uap) 483{ 484 485 return (kern_fsync(td, uap->fd, true)); 486} 487