svn commit: r286359 - head/sys/compat/cloudabi
Ed Schouten
ed at FreeBSD.org
Thu Aug 6 06:47:30 UTC 2015
Author: ed
Date: Thu Aug 6 06:47:28 2015
New Revision: 286359
URL: https://svnweb.freebsd.org/changeset/base/286359
Log:
Add file_open(): the underlying system call of openat().
CloudABI purely operates on file descriptor rights (CAP_*). File
descriptor access modes (O_ACCMODE) are emulated on top of rights.
Instead of accepting the traditional flags argument, file_open() copies
in an fdstat_t object that contains the initial rights the descriptor
should have, but also file descriptor flags that should persist after
opening (APPEND, NONBLOCK, *SYNC). Only flags that don't persist (EXCL,
TRUNC, CREAT, DIRECTORY) are passed in as an argument.
file_open() first converts the rights, the persistent flags and the
non-persistent flags to fflags. It then calls into vn_open(). If
successful, it installs the file descriptor with the requested
rights, trimming off rights that don't apply to the type of
the file that has been opened.
Unlike kern_openat(), this function does not support /dev/fd/*. I can't
think of a reason why we need to support this for CloudABI.
Obtained from: https://github.com/NuxiNL/freebsd
Differential Revision: https://reviews.freebsd.org/D3235
Modified:
head/sys/compat/cloudabi/cloudabi_fd.c
head/sys/compat/cloudabi/cloudabi_file.c
head/sys/compat/cloudabi/cloudabi_util.h
Modified: head/sys/compat/cloudabi/cloudabi_fd.c
==============================================================================
--- head/sys/compat/cloudabi/cloudabi_fd.c Thu Aug 6 01:49:18 2015 (r286358)
+++ head/sys/compat/cloudabi/cloudabi_fd.c Thu Aug 6 06:47:28 2015 (r286359)
@@ -290,7 +290,7 @@ cloudabi_convert_filetype(const struct f
}
/* 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)
{
@@ -499,6 +499,25 @@ cloudabi_sys_fd_stat_get(struct thread *
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)
Modified: head/sys/compat/cloudabi/cloudabi_file.c
==============================================================================
--- head/sys/compat/cloudabi/cloudabi_file.c Thu Aug 6 01:49:18 2015 (r286358)
+++ head/sys/compat/cloudabi/cloudabi_file.c Thu Aug 6 06:47:28 2015 (r286359)
@@ -197,9 +197,128 @@ 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;
+
+ 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);
- /* Not implemented. */
- return (ENOSYS);
+ /* 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. */
Modified: head/sys/compat/cloudabi/cloudabi_util.h
==============================================================================
--- head/sys/compat/cloudabi/cloudabi_util.h Thu Aug 6 01:49:18 2015 (r286358)
+++ head/sys/compat/cloudabi/cloudabi_util.h Thu Aug 6 06:47:28 2015 (r286359)
@@ -50,6 +50,13 @@ void cloudabi_convert_sockaddr(const str
/* 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 *);
More information about the svn-src-head
mailing list