Index: head/sys/compat/cloudabi/cloudabi_fd.c =================================================================== --- head/sys/compat/cloudabi/cloudabi_fd.c (revision 286358) +++ head/sys/compat/cloudabi/cloudabi_fd.c (revision 286359) @@ -1,536 +1,555 @@ /*- * Copyright (c) 2015 Nuxi, https://nuxi.nl/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Translation between CloudABI and Capsicum rights. */ #define RIGHTS_MAPPINGS \ MAPPING(CLOUDABI_RIGHT_FD_DATASYNC, CAP_FSYNC) \ MAPPING(CLOUDABI_RIGHT_FD_READ, CAP_READ) \ MAPPING(CLOUDABI_RIGHT_FD_SEEK, CAP_SEEK) \ MAPPING(CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS, CAP_FCNTL) \ MAPPING(CLOUDABI_RIGHT_FD_SYNC, CAP_FSYNC) \ MAPPING(CLOUDABI_RIGHT_FD_TELL, CAP_SEEK_TELL) \ MAPPING(CLOUDABI_RIGHT_FD_WRITE, CAP_WRITE) \ MAPPING(CLOUDABI_RIGHT_FILE_ADVISE) \ MAPPING(CLOUDABI_RIGHT_FILE_ALLOCATE, CAP_WRITE) \ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY, CAP_MKDIRAT) \ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FILE, CAP_CREATE) \ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FIFO, CAP_MKFIFOAT) \ MAPPING(CLOUDABI_RIGHT_FILE_LINK_SOURCE, CAP_LOOKUP) \ MAPPING(CLOUDABI_RIGHT_FILE_LINK_TARGET, CAP_LINKAT) \ MAPPING(CLOUDABI_RIGHT_FILE_OPEN, CAP_LOOKUP) \ MAPPING(CLOUDABI_RIGHT_FILE_READDIR, CAP_READ) \ MAPPING(CLOUDABI_RIGHT_FILE_READLINK, CAP_LOOKUP) \ MAPPING(CLOUDABI_RIGHT_FILE_RENAME_SOURCE, CAP_RENAMEAT) \ MAPPING(CLOUDABI_RIGHT_FILE_RENAME_TARGET, CAP_LINKAT) \ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FGET, CAP_FSTAT) \ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE, CAP_FTRUNCATE) \ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES, CAP_FUTIMES) \ MAPPING(CLOUDABI_RIGHT_FILE_STAT_GET, CAP_FSTATAT) \ MAPPING(CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES, CAP_FUTIMESAT) \ MAPPING(CLOUDABI_RIGHT_FILE_SYMLINK, CAP_SYMLINKAT) \ MAPPING(CLOUDABI_RIGHT_FILE_UNLINK, CAP_UNLINKAT) \ MAPPING(CLOUDABI_RIGHT_MEM_MAP, CAP_MMAP) \ MAPPING(CLOUDABI_RIGHT_MEM_MAP_EXEC, CAP_MMAP_X) \ MAPPING(CLOUDABI_RIGHT_POLL_FD_READWRITE, CAP_EVENT) \ MAPPING(CLOUDABI_RIGHT_POLL_MODIFY, CAP_KQUEUE_CHANGE) \ MAPPING(CLOUDABI_RIGHT_POLL_PROC_TERMINATE, CAP_PDWAIT) \ MAPPING(CLOUDABI_RIGHT_POLL_WAIT, CAP_KQUEUE_EVENT) \ MAPPING(CLOUDABI_RIGHT_PROC_EXEC, CAP_FEXECVE) \ MAPPING(CLOUDABI_RIGHT_SOCK_ACCEPT, CAP_ACCEPT) \ MAPPING(CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY, CAP_BINDAT) \ MAPPING(CLOUDABI_RIGHT_SOCK_BIND_SOCKET, CAP_BIND) \ MAPPING(CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY, CAP_CONNECTAT) \ MAPPING(CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET, CAP_CONNECT) \ MAPPING(CLOUDABI_RIGHT_SOCK_LISTEN, CAP_LISTEN) \ MAPPING(CLOUDABI_RIGHT_SOCK_SHUTDOWN, CAP_SHUTDOWN) \ MAPPING(CLOUDABI_RIGHT_SOCK_STAT_GET, CAP_GETPEERNAME, \ CAP_GETSOCKNAME, CAP_GETSOCKOPT) int cloudabi_sys_fd_close(struct thread *td, struct cloudabi_sys_fd_close_args *uap) { return (kern_close(td, uap->fd)); } int cloudabi_sys_fd_create1(struct thread *td, struct cloudabi_sys_fd_create1_args *uap) { struct filecaps fcaps = {}; struct socket_args socket_args = { .domain = AF_UNIX, }; switch (uap->type) { case CLOUDABI_FILETYPE_POLL: cap_rights_init(&fcaps.fc_rights, CAP_FSTAT, CAP_KQUEUE); return (kern_kqueue(td, 0, &fcaps)); case CLOUDABI_FILETYPE_SHARED_MEMORY: cap_rights_init(&fcaps.fc_rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_MMAP_RWX); return (kern_shm_open(td, SHM_ANON, O_RDWR, 0, &fcaps)); case CLOUDABI_FILETYPE_SOCKET_DGRAM: socket_args.type = SOCK_DGRAM; return (sys_socket(td, &socket_args)); case CLOUDABI_FILETYPE_SOCKET_SEQPACKET: socket_args.type = SOCK_SEQPACKET; return (sys_socket(td, &socket_args)); case CLOUDABI_FILETYPE_SOCKET_STREAM: socket_args.type = SOCK_STREAM; return (sys_socket(td, &socket_args)); default: return (EINVAL); } } int cloudabi_sys_fd_create2(struct thread *td, struct cloudabi_sys_fd_create2_args *uap) { struct filecaps fcaps1 = {}, fcaps2 = {}; int fds[2]; int error; switch (uap->type) { case CLOUDABI_FILETYPE_FIFO: /* * CloudABI pipes are unidirectional. Restrict rights on * the pipe to simulate this. */ cap_rights_init(&fcaps1.fc_rights, CAP_EVENT, CAP_FCNTL, CAP_FSTAT, CAP_READ); fcaps1.fc_fcntls = CAP_FCNTL_SETFL; cap_rights_init(&fcaps2.fc_rights, CAP_EVENT, CAP_FCNTL, CAP_FSTAT, CAP_WRITE); fcaps2.fc_fcntls = CAP_FCNTL_SETFL; error = kern_pipe(td, fds, 0, &fcaps1, &fcaps2); break; case CLOUDABI_FILETYPE_SOCKET_DGRAM: error = kern_socketpair(td, AF_UNIX, SOCK_DGRAM, 0, fds); break; case CLOUDABI_FILETYPE_SOCKET_SEQPACKET: error = kern_socketpair(td, AF_UNIX, SOCK_SEQPACKET, 0, fds); break; case CLOUDABI_FILETYPE_SOCKET_STREAM: error = kern_socketpair(td, AF_UNIX, SOCK_STREAM, 0, fds); break; default: return (EINVAL); } if (error == 0) { td->td_retval[0] = fds[0]; td->td_retval[1] = fds[1]; } return (0); } int cloudabi_sys_fd_datasync(struct thread *td, struct cloudabi_sys_fd_datasync_args *uap) { struct fsync_args fsync_args = { .fd = uap->fd }; /* Call into fsync(), as FreeBSD lacks fdatasync(). */ return (sys_fsync(td, &fsync_args)); } int cloudabi_sys_fd_dup(struct thread *td, struct cloudabi_sys_fd_dup_args *uap) { return (kern_dup(td, FDDUP_NORMAL, 0, uap->from, 0)); } int cloudabi_sys_fd_replace(struct thread *td, struct cloudabi_sys_fd_replace_args *uap) { int error; /* * CloudABI's equivalent to dup2(). CloudABI processes should * not depend on hardcoded file descriptor layouts, but simply * use the file descriptor numbers that are allocated by the * kernel. Duplicating file descriptors to arbitrary numbers * should not be done. * * Invoke kern_dup() with FDDUP_MUSTREPLACE, so that we return * EBADF when duplicating to a nonexistent file descriptor. Also * clear the return value, as this system call yields no return * value. */ error = kern_dup(td, FDDUP_MUSTREPLACE, 0, uap->from, uap->to); td->td_retval[0] = 0; return (error); } int cloudabi_sys_fd_seek(struct thread *td, struct cloudabi_sys_fd_seek_args *uap) { struct lseek_args lseek_args = { .fd = uap->fd, .offset = uap->offset }; switch (uap->whence) { case CLOUDABI_WHENCE_CUR: lseek_args.whence = SEEK_CUR; break; case CLOUDABI_WHENCE_END: lseek_args.whence = SEEK_END; break; case CLOUDABI_WHENCE_SET: lseek_args.whence = SEEK_SET; break; default: return (EINVAL); } return (sys_lseek(td, &lseek_args)); } /* Converts a file descriptor to a CloudABI file descriptor type. */ cloudabi_filetype_t cloudabi_convert_filetype(const struct file *fp) { struct socket *so; struct vnode *vp; switch (fp->f_type) { case DTYPE_FIFO: return (CLOUDABI_FILETYPE_FIFO); case DTYPE_KQUEUE: return (CLOUDABI_FILETYPE_POLL); case DTYPE_PIPE: return (CLOUDABI_FILETYPE_FIFO); case DTYPE_PROCDESC: return (CLOUDABI_FILETYPE_PROCESS); case DTYPE_SHM: return (CLOUDABI_FILETYPE_SHARED_MEMORY); case DTYPE_SOCKET: so = fp->f_data; switch (so->so_type) { case SOCK_DGRAM: return (CLOUDABI_FILETYPE_SOCKET_DGRAM); case SOCK_SEQPACKET: return (CLOUDABI_FILETYPE_SOCKET_SEQPACKET); case SOCK_STREAM: return (CLOUDABI_FILETYPE_SOCKET_STREAM); default: return (CLOUDABI_FILETYPE_UNKNOWN); } case DTYPE_VNODE: vp = fp->f_vnode; switch (vp->v_type) { case VBLK: return (CLOUDABI_FILETYPE_BLOCK_DEVICE); case VCHR: return (CLOUDABI_FILETYPE_CHARACTER_DEVICE); case VDIR: return (CLOUDABI_FILETYPE_DIRECTORY); case VFIFO: return (CLOUDABI_FILETYPE_FIFO); case VLNK: return (CLOUDABI_FILETYPE_SYMBOLIC_LINK); case VREG: return (CLOUDABI_FILETYPE_REGULAR_FILE); case VSOCK: return (CLOUDABI_FILETYPE_SOCKET_STREAM); default: return (CLOUDABI_FILETYPE_UNKNOWN); } default: return (CLOUDABI_FILETYPE_UNKNOWN); } } /* Removes rights that conflict with the file descriptor type. */ -static void +void cloudabi_remove_conflicting_rights(cloudabi_filetype_t filetype, cloudabi_rights_t *base, cloudabi_rights_t *inheriting) { /* * CloudABI has a small number of additional rights bits to * disambiguate between multiple purposes. Remove the bits that * don't apply to the type of the file descriptor. * * As file descriptor access modes (O_ACCMODE) has been fully * replaced by rights bits, CloudABI distinguishes between * rights that apply to the file descriptor itself (base) versus * rights of new file descriptors derived from them * (inheriting). The code below approximates the pair by * decomposing depending on the file descriptor type. * * We need to be somewhat accurate about which actions can * actually be performed on the file descriptor, as functions * like fcntl(fd, F_GETFL) are emulated on top of this. */ switch (filetype) { case CLOUDABI_FILETYPE_DIRECTORY: *base &= CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | CLOUDABI_RIGHT_FD_SYNC | CLOUDABI_RIGHT_FILE_ADVISE | CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY | CLOUDABI_RIGHT_FILE_CREATE_FILE | CLOUDABI_RIGHT_FILE_CREATE_FIFO | CLOUDABI_RIGHT_FILE_LINK_SOURCE | CLOUDABI_RIGHT_FILE_LINK_TARGET | CLOUDABI_RIGHT_FILE_OPEN | CLOUDABI_RIGHT_FILE_READDIR | CLOUDABI_RIGHT_FILE_READLINK | CLOUDABI_RIGHT_FILE_RENAME_SOURCE | CLOUDABI_RIGHT_FILE_RENAME_TARGET | CLOUDABI_RIGHT_FILE_STAT_FGET | CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES | CLOUDABI_RIGHT_FILE_STAT_GET | CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES | CLOUDABI_RIGHT_FILE_SYMLINK | CLOUDABI_RIGHT_FILE_UNLINK | CLOUDABI_RIGHT_POLL_FD_READWRITE | CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY | CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY; *inheriting &= CLOUDABI_RIGHT_FD_DATASYNC | CLOUDABI_RIGHT_FD_READ | CLOUDABI_RIGHT_FD_SEEK | CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | CLOUDABI_RIGHT_FD_SYNC | CLOUDABI_RIGHT_FD_TELL | CLOUDABI_RIGHT_FD_WRITE | CLOUDABI_RIGHT_FILE_ADVISE | CLOUDABI_RIGHT_FILE_ALLOCATE | CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY | CLOUDABI_RIGHT_FILE_CREATE_FILE | CLOUDABI_RIGHT_FILE_CREATE_FIFO | CLOUDABI_RIGHT_FILE_LINK_SOURCE | CLOUDABI_RIGHT_FILE_LINK_TARGET | CLOUDABI_RIGHT_FILE_OPEN | CLOUDABI_RIGHT_FILE_READDIR | CLOUDABI_RIGHT_FILE_READLINK | CLOUDABI_RIGHT_FILE_RENAME_SOURCE | CLOUDABI_RIGHT_FILE_RENAME_TARGET | CLOUDABI_RIGHT_FILE_STAT_FGET | CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE | CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES | CLOUDABI_RIGHT_FILE_STAT_GET | CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES | CLOUDABI_RIGHT_FILE_SYMLINK | CLOUDABI_RIGHT_FILE_UNLINK | CLOUDABI_RIGHT_MEM_MAP | CLOUDABI_RIGHT_MEM_MAP_EXEC | CLOUDABI_RIGHT_POLL_FD_READWRITE | CLOUDABI_RIGHT_PROC_EXEC | CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY | CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY; break; case CLOUDABI_FILETYPE_FIFO: *base &= CLOUDABI_RIGHT_FD_READ | CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | CLOUDABI_RIGHT_FD_WRITE | CLOUDABI_RIGHT_FILE_STAT_FGET | CLOUDABI_RIGHT_POLL_FD_READWRITE; *inheriting = 0; break; case CLOUDABI_FILETYPE_POLL: *base &= ~CLOUDABI_RIGHT_FILE_ADVISE; *inheriting = 0; break; case CLOUDABI_FILETYPE_PROCESS: *base &= ~CLOUDABI_RIGHT_FILE_ADVISE; *inheriting = 0; break; case CLOUDABI_FILETYPE_REGULAR_FILE: *base &= CLOUDABI_RIGHT_FD_DATASYNC | CLOUDABI_RIGHT_FD_READ | CLOUDABI_RIGHT_FD_SEEK | CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | CLOUDABI_RIGHT_FD_SYNC | CLOUDABI_RIGHT_FD_TELL | CLOUDABI_RIGHT_FD_WRITE | CLOUDABI_RIGHT_FILE_ADVISE | CLOUDABI_RIGHT_FILE_ALLOCATE | CLOUDABI_RIGHT_FILE_STAT_FGET | CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE | CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES | CLOUDABI_RIGHT_MEM_MAP | CLOUDABI_RIGHT_MEM_MAP_EXEC | CLOUDABI_RIGHT_POLL_FD_READWRITE | CLOUDABI_RIGHT_PROC_EXEC; *inheriting = 0; break; case CLOUDABI_FILETYPE_SHARED_MEMORY: *base &= ~(CLOUDABI_RIGHT_FD_SEEK | CLOUDABI_RIGHT_FD_TELL | CLOUDABI_RIGHT_FILE_ADVISE | CLOUDABI_RIGHT_FILE_ALLOCATE | CLOUDABI_RIGHT_FILE_READDIR); *inheriting = 0; break; case CLOUDABI_FILETYPE_SOCKET_DGRAM: case CLOUDABI_FILETYPE_SOCKET_SEQPACKET: case CLOUDABI_FILETYPE_SOCKET_STREAM: *base &= CLOUDABI_RIGHT_FD_READ | CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS | CLOUDABI_RIGHT_FD_WRITE | CLOUDABI_RIGHT_FILE_STAT_FGET | CLOUDABI_RIGHT_POLL_FD_READWRITE | CLOUDABI_RIGHT_SOCK_ACCEPT | CLOUDABI_RIGHT_SOCK_BIND_SOCKET | CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET | CLOUDABI_RIGHT_SOCK_LISTEN | CLOUDABI_RIGHT_SOCK_SHUTDOWN | CLOUDABI_RIGHT_SOCK_STAT_GET; break; default: *inheriting = 0; break; } } /* Converts FreeBSD's Capsicum rights to CloudABI's set of rights. */ static void convert_capabilities(const cap_rights_t *capabilities, cloudabi_filetype_t filetype, cloudabi_rights_t *base, cloudabi_rights_t *inheriting) { cloudabi_rights_t rights; /* Convert FreeBSD bits to CloudABI bits. */ rights = 0; #define MAPPING(cloudabi, ...) do { \ if (cap_rights_is_set(capabilities, ##__VA_ARGS__)) \ rights |= (cloudabi); \ } while (0); RIGHTS_MAPPINGS #undef MAPPING *base = rights; *inheriting = rights; cloudabi_remove_conflicting_rights(filetype, base, inheriting); } int cloudabi_sys_fd_stat_get(struct thread *td, struct cloudabi_sys_fd_stat_get_args *uap) { cloudabi_fdstat_t fsb = {}; struct filedesc *fdp; struct file *fp; seq_t seq; cap_rights_t rights; int error, oflags; bool modified; /* Obtain file descriptor properties. */ fdp = td->td_proc->p_fd; do { error = fget_unlocked(fdp, uap->fd, cap_rights_init(&rights), &fp, &seq); if (error != 0) return (error); if (fp->f_ops == &badfileops) { fdrop(fp, td); return (EBADF); } rights = *cap_rights(fdp, uap->fd); oflags = OFLAGS(fp->f_flag); fsb.fs_filetype = cloudabi_convert_filetype(fp); modified = fd_modified(fdp, uap->fd, seq); fdrop(fp, td); } while (modified); /* Convert file descriptor flags. */ if (oflags & O_APPEND) fsb.fs_flags |= CLOUDABI_FDFLAG_APPEND; if (oflags & O_NONBLOCK) fsb.fs_flags |= CLOUDABI_FDFLAG_NONBLOCK; if (oflags & O_SYNC) fsb.fs_flags |= CLOUDABI_FDFLAG_SYNC; /* Convert capabilities to CloudABI rights. */ convert_capabilities(&rights, fsb.fs_filetype, &fsb.fs_rights_base, &fsb.fs_rights_inheriting); return (copyout(&fsb, (void *)uap->buf, sizeof(fsb))); +} + +/* Converts CloudABI rights to a set of Capsicum capabilities. */ +int +cloudabi_convert_rights(cloudabi_rights_t in, cap_rights_t *out) +{ + + cap_rights_init(out); +#define MAPPING(cloudabi, ...) do { \ + if (in & (cloudabi)) { \ + cap_rights_set(out, ##__VA_ARGS__); \ + in &= ~(cloudabi); \ + } \ +} while (0); + RIGHTS_MAPPINGS +#undef MAPPING + if (in != 0) + return (ENOTCAPABLE); + return (0); } int cloudabi_sys_fd_stat_put(struct thread *td, struct cloudabi_sys_fd_stat_put_args *uap) { cloudabi_fdstat_t fsb; int error, oflags; error = copyin(uap->buf, &fsb, sizeof(fsb)); if (error != 0) return (error); if (uap->flags == CLOUDABI_FDSTAT_FLAGS) { /* Convert flags. */ oflags = 0; if (fsb.fs_flags & CLOUDABI_FDFLAG_APPEND) oflags |= O_APPEND; if (fsb.fs_flags & CLOUDABI_FDFLAG_NONBLOCK) oflags |= O_NONBLOCK; if (fsb.fs_flags & (CLOUDABI_FDFLAG_SYNC | CLOUDABI_FDFLAG_DSYNC | CLOUDABI_FDFLAG_RSYNC)) oflags |= O_SYNC; return (kern_fcntl(td, uap->fd, F_SETFL, oflags)); } return (EINVAL); } int cloudabi_sys_fd_sync(struct thread *td, struct cloudabi_sys_fd_sync_args *uap) { struct fsync_args fsync_args = { .fd = uap->fd }; return (sys_fsync(td, &fsync_args)); } Index: head/sys/compat/cloudabi/cloudabi_file.c =================================================================== --- head/sys/compat/cloudabi/cloudabi_file.c (revision 286358) +++ head/sys/compat/cloudabi/cloudabi_file.c (revision 286359) @@ -1,641 +1,760 @@ /*- * Copyright (c) 2015 Nuxi, https://nuxi.nl/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames"); /* * Copying pathnames from userspace to kernelspace. * * Unlike most operating systems, CloudABI doesn't use null-terminated * pathname strings. Processes always pass pathnames to the kernel by * providing a base pointer and a length. This has a couple of reasons: * * - It makes it easier to use CloudABI in combination with programming * languages other than C, that may use non-null terminated strings. * - It allows for calling system calls on individual components of the * pathname without modifying the input string. * * The function below copies in pathname strings and null-terminates it. * It also ensure that the string itself does not contain any null * bytes. * * TODO(ed): Add an abstraction to vfs_lookup.c that allows us to pass * in unterminated pathname strings, so we can do away with * the copying. */ static int copyin_path(const char *uaddr, size_t len, char **result) { char *buf; int error; if (len >= PATH_MAX) return (ENAMETOOLONG); buf = malloc(len + 1, M_CLOUDABI_PATH, M_WAITOK); error = copyin(uaddr, buf, len); if (error != 0) { free(buf, M_CLOUDABI_PATH); return (error); } if (memchr(buf, '\0', len) != NULL) { free(buf, M_CLOUDABI_PATH); return (EINVAL); } buf[len] = '\0'; *result = buf; return (0); } static void cloudabi_freestr(char *buf) { free(buf, M_CLOUDABI_PATH); } int cloudabi_sys_file_advise(struct thread *td, struct cloudabi_sys_file_advise_args *uap) { int advice; switch (uap->advice) { case CLOUDABI_ADVICE_DONTNEED: advice = POSIX_FADV_DONTNEED; break; case CLOUDABI_ADVICE_NOREUSE: advice = POSIX_FADV_NOREUSE; break; case CLOUDABI_ADVICE_NORMAL: advice = POSIX_FADV_NORMAL; break; case CLOUDABI_ADVICE_RANDOM: advice = POSIX_FADV_RANDOM; break; case CLOUDABI_ADVICE_SEQUENTIAL: advice = POSIX_FADV_SEQUENTIAL; break; case CLOUDABI_ADVICE_WILLNEED: advice = POSIX_FADV_WILLNEED; break; default: return (EINVAL); } return (kern_posix_fadvise(td, uap->fd, uap->offset, uap->len, advice)); } int cloudabi_sys_file_allocate(struct thread *td, struct cloudabi_sys_file_allocate_args *uap) { return (kern_posix_fallocate(td, uap->fd, uap->offset, uap->len)); } int cloudabi_sys_file_create(struct thread *td, struct cloudabi_sys_file_create_args *uap) { char *path; int error; error = copyin_path(uap->path, uap->pathlen, &path); if (error != 0) return (error); /* * CloudABI processes cannot interact with UNIX credentials and * permissions. Depend on the umask that is set prior to * execution to restrict the file permissions. */ switch (uap->type) { case CLOUDABI_FILETYPE_DIRECTORY: error = kern_mkdirat(td, uap->fd, path, UIO_SYSSPACE, 0777); break; case CLOUDABI_FILETYPE_FIFO: error = kern_mkfifoat(td, uap->fd, path, UIO_SYSSPACE, 0666); break; default: error = EINVAL; break; } cloudabi_freestr(path); return (error); } int cloudabi_sys_file_link(struct thread *td, struct cloudabi_sys_file_link_args *uap) { char *path1, *path2; int error; error = copyin_path(uap->path1, uap->path1len, &path1); if (error != 0) return (error); error = copyin_path(uap->path2, uap->path2len, &path2); if (error != 0) { cloudabi_freestr(path1); return (error); } error = kern_linkat(td, uap->fd1, uap->fd2, path1, path2, UIO_SYSSPACE, (uap->fd1 & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? FOLLOW : NOFOLLOW); cloudabi_freestr(path1); cloudabi_freestr(path2); return (error); } int cloudabi_sys_file_open(struct thread *td, struct cloudabi_sys_file_open_args *uap) { + cloudabi_fdstat_t fds; + cap_rights_t rights; + struct filecaps fcaps = {}; + struct nameidata nd; + struct file *fp; + struct vnode *vp; + char *path; + int error, fd, fflags; + bool read, write; - /* Not implemented. */ - return (ENOSYS); + error = copyin(uap->fds, &fds, sizeof(fds)); + if (error != 0) + return (error); + + /* All the requested rights should be set on the descriptor. */ + error = cloudabi_convert_rights( + fds.fs_rights_base | fds.fs_rights_inheriting, &rights); + if (error != 0) + return (error); + cap_rights_set(&rights, CAP_LOOKUP); + + /* Convert rights to corresponding access mode. */ + read = (fds.fs_rights_base & (CLOUDABI_RIGHT_FD_READ | + CLOUDABI_RIGHT_FILE_READDIR | CLOUDABI_RIGHT_MEM_MAP_EXEC)) != 0; + write = (fds.fs_rights_base & (CLOUDABI_RIGHT_FD_DATASYNC | + CLOUDABI_RIGHT_FD_WRITE | CLOUDABI_RIGHT_FILE_ALLOCATE | + CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE)) != 0; + fflags = read ? write ? FREAD | FWRITE : FREAD : FWRITE; + + /* Convert open flags. */ + if ((uap->oflags & CLOUDABI_O_CREAT) != 0) { + fflags |= O_CREAT; + cap_rights_set(&rights, CAP_CREATE); + } + if ((uap->oflags & CLOUDABI_O_DIRECTORY) != 0) + fflags |= O_DIRECTORY; + if ((uap->oflags & CLOUDABI_O_EXCL) != 0) + fflags |= O_EXCL; + if ((uap->oflags & CLOUDABI_O_TRUNC) != 0) { + fflags |= O_TRUNC; + cap_rights_set(&rights, CAP_FTRUNCATE); + } + if ((fds.fs_flags & CLOUDABI_FDFLAG_APPEND) != 0) + fflags |= O_APPEND; + if ((fds.fs_flags & CLOUDABI_FDFLAG_NONBLOCK) != 0) + fflags |= O_NONBLOCK; + if ((fds.fs_flags & (CLOUDABI_FDFLAG_SYNC | CLOUDABI_FDFLAG_DSYNC | + CLOUDABI_FDFLAG_RSYNC)) != 0) { + fflags |= O_SYNC; + cap_rights_set(&rights, CAP_FSYNC); + } + if ((uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) == 0) + fflags |= O_NOFOLLOW; + if (write && (fflags & (O_APPEND | O_TRUNC)) == 0) + cap_rights_set(&rights, CAP_SEEK); + + /* Allocate new file descriptor. */ + error = falloc_noinstall(td, &fp); + if (error != 0) + return (error); + fp->f_flag = fflags & FMASK; + + /* Open path. */ + error = copyin_path(uap->path, uap->pathlen, &path); + if (error != 0) { + fdrop(fp, td); + return (error); + } + NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, uap->fd, + &rights, td); + error = vn_open(&nd, &fflags, 0777 & ~td->td_proc->p_fd->fd_cmask, fp); + cloudabi_freestr(path); + if (error != 0) { + /* Custom operations provided. */ + if (error == ENXIO && fp->f_ops != &badfileops) + goto success; + + /* + * POSIX compliance: return ELOOP in case openat() is + * called on a symbolic link and O_NOFOLLOW is set. + */ + if (error == EMLINK) + error = ELOOP; + fdrop(fp, td); + return (error); + } + NDFREE(&nd, NDF_ONLY_PNBUF); + filecaps_free(&nd.ni_filecaps); + fp->f_vnode = vp = nd.ni_vp; + + /* Install vnode operations if no custom operations are provided. */ + if (fp->f_ops == &badfileops) { + fp->f_seqcount = 1; + finit(fp, (fflags & FMASK) | (fp->f_flag & FHASLOCK), + DTYPE_VNODE, vp, &vnops); + } + VOP_UNLOCK(vp, 0); + + /* Truncate file. */ + if (fflags & O_TRUNC) { + error = fo_truncate(fp, 0, td->td_ucred, td); + if (error != 0) { + fdrop(fp, td); + return (error); + } + } + +success: + /* Determine which Capsicum rights to set on the file descriptor. */ + cloudabi_remove_conflicting_rights(cloudabi_convert_filetype(fp), + &fds.fs_rights_base, &fds.fs_rights_inheriting); + cloudabi_convert_rights(fds.fs_rights_base | fds.fs_rights_inheriting, + &fcaps.fc_rights); + if (cap_rights_is_set(&fcaps.fc_rights)) + fcaps.fc_fcntls = CAP_FCNTL_SETFL; + + error = finstall(td, fp, &fd, fflags, &fcaps); + fdrop(fp, td); + if (error != 0) + return (error); + td->td_retval[0] = fd; + return (0); } /* Converts a FreeBSD directory entry structure and writes it to userspace. */ static int write_dirent(struct dirent *bde, cloudabi_dircookie_t cookie, struct uio *uio) { cloudabi_dirent_t cde = { .d_next = cookie, .d_ino = bde->d_fileno, .d_namlen = bde->d_namlen, }; size_t len; int error; /* Convert file type. */ switch (bde->d_type) { case DT_BLK: cde.d_type = CLOUDABI_FILETYPE_BLOCK_DEVICE; break; case DT_CHR: cde.d_type = CLOUDABI_FILETYPE_CHARACTER_DEVICE; break; case DT_DIR: cde.d_type = CLOUDABI_FILETYPE_DIRECTORY; break; case DT_FIFO: cde.d_type = CLOUDABI_FILETYPE_FIFO; break; case DT_LNK: cde.d_type = CLOUDABI_FILETYPE_SYMBOLIC_LINK; break; case DT_REG: cde.d_type = CLOUDABI_FILETYPE_REGULAR_FILE; break; case DT_SOCK: /* The exact socket type cannot be derived. */ cde.d_type = CLOUDABI_FILETYPE_SOCKET_STREAM; break; default: cde.d_type = CLOUDABI_FILETYPE_UNKNOWN; break; } /* Write directory entry structure. */ len = sizeof(cde) < uio->uio_resid ? sizeof(cde) : uio->uio_resid; error = uiomove(&cde, len, uio); if (error != 0) return (error); /* Write filename. */ len = bde->d_namlen < uio->uio_resid ? bde->d_namlen : uio->uio_resid; return (uiomove(bde->d_name, len, uio)); } int cloudabi_sys_file_readdir(struct thread *td, struct cloudabi_sys_file_readdir_args *uap) { struct iovec iov = { .iov_base = uap->buf, .iov_len = uap->nbyte }; struct uio uio = { .uio_iov = &iov, .uio_iovcnt = 1, .uio_resid = iov.iov_len, .uio_segflg = UIO_USERSPACE, .uio_rw = UIO_READ, .uio_td = td }; struct file *fp; struct vnode *vp; void *readbuf; cap_rights_t rights; cloudabi_dircookie_t offset; int error; /* Obtain directory vnode. */ error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp); if (error != 0) { if (error == EINVAL) return (ENOTDIR); return (error); } if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); return (EBADF); } /* * Call VOP_READDIR() and convert resulting data until the user * provided buffer is filled. */ readbuf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); offset = uap->cookie; vp = fp->f_vnode; while (uio.uio_resid > 0) { struct iovec readiov = { .iov_base = readbuf, .iov_len = MAXBSIZE }; struct uio readuio = { .uio_iov = &readiov, .uio_iovcnt = 1, .uio_rw = UIO_READ, .uio_segflg = UIO_SYSSPACE, .uio_td = td, .uio_resid = MAXBSIZE, .uio_offset = offset }; struct dirent *bde; unsigned long *cookies, *cookie; size_t readbuflen; int eof, ncookies; /* Validate file type. */ vn_lock(vp, LK_SHARED | LK_RETRY); if (vp->v_type != VDIR) { VOP_UNLOCK(vp, 0); error = ENOTDIR; goto done; } #ifdef MAC error = mac_vnode_check_readdir(td->td_ucred, vp); if (error != 0) { VOP_UNLOCK(vp, 0); goto done; } #endif /* MAC */ /* Read new directory entries. */ cookies = NULL; ncookies = 0; error = VOP_READDIR(vp, &readuio, fp->f_cred, &eof, &ncookies, &cookies); VOP_UNLOCK(vp, 0); if (error != 0) goto done; /* Convert entries to CloudABI's format. */ readbuflen = MAXBSIZE - readuio.uio_resid; bde = readbuf; cookie = cookies; while (readbuflen >= offsetof(struct dirent, d_name) && uio.uio_resid > 0 && ncookies > 0) { /* Ensure that the returned offset always increases. */ if (readbuflen >= bde->d_reclen && bde->d_fileno != 0 && *cookie > offset) { error = write_dirent(bde, *cookie, &uio); if (error != 0) { free(cookies, M_TEMP); goto done; } } if (offset < *cookie) offset = *cookie; ++cookie; --ncookies; readbuflen -= bde->d_reclen; bde = (struct dirent *)((char *)bde + bde->d_reclen); } free(cookies, M_TEMP); if (eof) break; } done: fdrop(fp, td); free(readbuf, M_TEMP); if (error != 0) return (error); /* Return number of bytes copied to userspace. */ td->td_retval[0] = uap->nbyte - uio.uio_resid; return (0); } int cloudabi_sys_file_readlink(struct thread *td, struct cloudabi_sys_file_readlink_args *uap) { char *path; int error; error = copyin_path(uap->path, uap->pathlen, &path); if (error != 0) return (error); error = kern_readlinkat(td, uap->fd, path, UIO_SYSSPACE, uap->buf, UIO_USERSPACE, uap->bufsize); cloudabi_freestr(path); return (error); } int cloudabi_sys_file_rename(struct thread *td, struct cloudabi_sys_file_rename_args *uap) { char *old, *new; int error; error = copyin_path(uap->old, uap->oldlen, &old); if (error != 0) return (error); error = copyin_path(uap->new, uap->newlen, &new); if (error != 0) { cloudabi_freestr(old); return (error); } error = kern_renameat(td, uap->oldfd, old, uap->newfd, new, UIO_SYSSPACE); cloudabi_freestr(old); cloudabi_freestr(new); return (error); } /* Converts a FreeBSD stat structure to a CloudABI stat structure. */ static void convert_stat(const struct stat *sb, cloudabi_filestat_t *csb) { cloudabi_filestat_t res = { .st_dev = sb->st_dev, .st_ino = sb->st_ino, .st_nlink = sb->st_nlink, .st_size = sb->st_size, }; cloudabi_convert_timespec(&sb->st_atim, &res.st_atim); cloudabi_convert_timespec(&sb->st_mtim, &res.st_mtim); cloudabi_convert_timespec(&sb->st_ctim, &res.st_ctim); *csb = res; } int cloudabi_sys_file_stat_fget(struct thread *td, struct cloudabi_sys_file_stat_fget_args *uap) { struct stat sb; cloudabi_filestat_t csb; struct file *fp; cap_rights_t rights; cloudabi_filetype_t filetype; int error; /* Fetch file descriptor attributes. */ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FSTAT), &fp); if (error != 0) return (error); error = fo_stat(fp, &sb, td->td_ucred, td); if (error != 0) { fdrop(fp, td); return (error); } filetype = cloudabi_convert_filetype(fp); fdrop(fp, td); /* Convert attributes to CloudABI's format. */ convert_stat(&sb, &csb); csb.st_filetype = filetype; return (copyout(&csb, uap->buf, sizeof(csb))); } /* Converts timestamps to arguments to futimens() and utimensat(). */ static void convert_utimens_arguments(const cloudabi_filestat_t *fs, cloudabi_fsflags_t flags, struct timespec *ts) { if ((flags & CLOUDABI_FILESTAT_ATIM_NOW) != 0) { ts[0].tv_nsec = UTIME_NOW; } else if ((flags & CLOUDABI_FILESTAT_ATIM) != 0) { ts[0].tv_sec = fs->st_atim / 1000000000; ts[0].tv_nsec = fs->st_atim % 1000000000; } else { ts[0].tv_nsec = UTIME_OMIT; } if ((flags & CLOUDABI_FILESTAT_MTIM_NOW) != 0) { ts[1].tv_nsec = UTIME_NOW; } else if ((flags & CLOUDABI_FILESTAT_MTIM) != 0) { ts[1].tv_sec = fs->st_mtim / 1000000000; ts[1].tv_nsec = fs->st_mtim % 1000000000; } else { ts[1].tv_nsec = UTIME_OMIT; } } int cloudabi_sys_file_stat_fput(struct thread *td, struct cloudabi_sys_file_stat_fput_args *uap) { cloudabi_filestat_t fs; struct timespec ts[2]; int error; error = copyin(uap->buf, &fs, sizeof(fs)); if (error != 0) return (error); /* * Only support truncation and timestamp modification separately * for now, to prevent unnecessary code duplication. */ if ((uap->flags & CLOUDABI_FILESTAT_SIZE) != 0) { /* Call into kern_ftruncate() for file truncation. */ if ((uap->flags & ~CLOUDABI_FILESTAT_SIZE) != 0) return (EINVAL); return (kern_ftruncate(td, uap->fd, fs.st_size)); } else if ((uap->flags & (CLOUDABI_FILESTAT_ATIM | CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM | CLOUDABI_FILESTAT_MTIM_NOW)) != 0) { /* Call into kern_futimens() for timestamp modification. */ if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM | CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM | CLOUDABI_FILESTAT_MTIM_NOW)) != 0) return (EINVAL); convert_utimens_arguments(&fs, uap->flags, ts); return (kern_futimens(td, uap->fd, ts, UIO_SYSSPACE)); } return (EINVAL); } int cloudabi_sys_file_stat_get(struct thread *td, struct cloudabi_sys_file_stat_get_args *uap) { struct stat sb; cloudabi_filestat_t csb; char *path; int error; error = copyin_path(uap->path, uap->pathlen, &path); if (error != 0) return (error); error = kern_statat(td, (uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 : AT_SYMLINK_NOFOLLOW, uap->fd, path, UIO_SYSSPACE, &sb, NULL); cloudabi_freestr(path); if (error != 0) return (error); /* Convert results and return them. */ convert_stat(&sb, &csb); if (S_ISBLK(sb.st_mode)) csb.st_filetype = CLOUDABI_FILETYPE_BLOCK_DEVICE; else if (S_ISCHR(sb.st_mode)) csb.st_filetype = CLOUDABI_FILETYPE_CHARACTER_DEVICE; else if (S_ISDIR(sb.st_mode)) csb.st_filetype = CLOUDABI_FILETYPE_DIRECTORY; else if (S_ISFIFO(sb.st_mode)) csb.st_filetype = CLOUDABI_FILETYPE_FIFO; else if (S_ISREG(sb.st_mode)) csb.st_filetype = CLOUDABI_FILETYPE_REGULAR_FILE; else if (S_ISSOCK(sb.st_mode)) { /* Inaccurate, but the best that we can do. */ csb.st_filetype = CLOUDABI_FILETYPE_SOCKET_STREAM; } else if (S_ISLNK(sb.st_mode)) csb.st_filetype = CLOUDABI_FILETYPE_SYMBOLIC_LINK; else csb.st_filetype = CLOUDABI_FILETYPE_UNKNOWN; return (copyout(&csb, uap->buf, sizeof(csb))); } int cloudabi_sys_file_stat_put(struct thread *td, struct cloudabi_sys_file_stat_put_args *uap) { cloudabi_filestat_t fs; struct timespec ts[2]; char *path; int error; /* * Only support timestamp modification for now, as there is no * truncateat(). */ if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM | CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM | CLOUDABI_FILESTAT_MTIM_NOW)) != 0) return (EINVAL); error = copyin(uap->buf, &fs, sizeof(fs)); if (error != 0) return (error); error = copyin_path(uap->path, uap->pathlen, &path); if (error != 0) return (error); convert_utimens_arguments(&fs, uap->flags, ts); error = kern_utimensat(td, uap->fd, path, UIO_SYSSPACE, ts, UIO_SYSSPACE, (uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 : AT_SYMLINK_NOFOLLOW); cloudabi_freestr(path); return (error); } int cloudabi_sys_file_symlink(struct thread *td, struct cloudabi_sys_file_symlink_args *uap) { char *path1, *path2; int error; error = copyin_path(uap->path1, uap->path1len, &path1); if (error != 0) return (error); error = copyin_path(uap->path2, uap->path2len, &path2); if (error != 0) { cloudabi_freestr(path1); return (error); } error = kern_symlinkat(td, path1, uap->fd, path2, UIO_SYSSPACE); cloudabi_freestr(path1); cloudabi_freestr(path2); return (error); } int cloudabi_sys_file_unlink(struct thread *td, struct cloudabi_sys_file_unlink_args *uap) { char *path; int error; error = copyin_path(uap->path, uap->pathlen, &path); if (error != 0) return (error); if (uap->flag & CLOUDABI_UNLINK_REMOVEDIR) error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE); else error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0); cloudabi_freestr(path); return (error); } Index: head/sys/compat/cloudabi/cloudabi_util.h =================================================================== --- head/sys/compat/cloudabi/cloudabi_util.h (revision 286358) +++ head/sys/compat/cloudabi/cloudabi_util.h (revision 286359) @@ -1,72 +1,79 @@ /*- * Copyright (c) 2015 Nuxi, https://nuxi.nl/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _CLOUDABI_UTIL_H_ #define _CLOUDABI_UTIL_H_ #include #include struct file; struct thread; struct timespec; /* Fetches the time value of a clock. */ int cloudabi_clock_time_get(struct thread *, cloudabi_clockid_t, cloudabi_timestamp_t *); /* Converts a FreeBSD errno to a CloudABI errno. */ cloudabi_errno_t cloudabi_convert_errno(int); /* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */ void cloudabi_convert_sockaddr(const struct sockaddr *, socklen_t, cloudabi_sockaddr_t *); /* Converts a file descriptor to a CloudABI file descriptor type. */ cloudabi_filetype_t cloudabi_convert_filetype(const struct file *); +/* Converts CloudABI rights to a set of Capsicum capabilities. */ +int cloudabi_convert_rights(cloudabi_rights_t, cap_rights_t *); + +/* Removes rights that conflict with the file descriptor type. */ +void cloudabi_remove_conflicting_rights(cloudabi_filetype_t, + cloudabi_rights_t *, cloudabi_rights_t *); + /* Converts a struct timespec to a CloudABI timestamp. */ int cloudabi_convert_timespec(const struct timespec *, cloudabi_timestamp_t *); /* * Blocking futex functions. * * These functions are called by CloudABI's polling system calls to * sleep on a lock or condition variable. */ int cloudabi_futex_condvar_wait(struct thread *, cloudabi_condvar_t *, cloudabi_mflags_t, cloudabi_lock_t *, cloudabi_mflags_t, cloudabi_clockid_t, cloudabi_timestamp_t, cloudabi_timestamp_t); int cloudabi_futex_lock_rdlock(struct thread *, cloudabi_lock_t *, cloudabi_mflags_t, cloudabi_clockid_t, cloudabi_timestamp_t, cloudabi_timestamp_t); int cloudabi_futex_lock_wrlock(struct thread *, cloudabi_lock_t *, cloudabi_mflags_t, cloudabi_clockid_t, cloudabi_timestamp_t, cloudabi_timestamp_t); #endif