/*
- * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/user.h>
#include <sys/lockf.h>
#include <sys/xattr.h>
+#include <sys/kdebug.h>
#include <kern/assert.h>
#include <kern/kalloc.h>
#include <kern/task.h>
+#include <kern/policy_internal.h>
#include <libkern/OSByteOrder.h>
#include <security/mac_framework.h>
#endif
+#if NULLFS
+#include <miscfs/nullfs/nullfs.h>
+#endif
+
#include <sys/sdt.h>
#define ESUCCESS 0
if (proc->p_lflag & P_LRAGE_VNODES) {
return 1;
}
-
+
if (ut) {
- if (ut->uu_flag & UT_RAGE_VNODES) {
+ if (ut->uu_flag & (UT_RAGE_VNODES | UT_ATIME_UPDATE)) {
return 1;
}
}
+
+ if (proc->p_vfs_iopolicy & P_VFS_IOPOLICY_ATIME_UPDATES) {
+ return 1;
+ }
}
return 0;
}
/* how many entries would fit? */
fsec_size = KAUTH_FILESEC_COUNT(xsize);
+ if (fsec_size > KAUTH_ACL_MAX_ENTRIES) {
+ KAUTH_DEBUG(" ERROR - Bogus (too large) kauth_fiilesec_t: %ld bytes", xsize);
+ error = 0;
+ goto out;
+ }
/* get buffer and uio */
if (((fsec = kauth_filesec_alloc(fsec_size)) == NULL) ||
/*
* Returns: 0 Success
* ENOMEM Not enough space [only if has filesec]
+ * EINVAL Requested unknown attributes
* VNOP_GETATTR: ???
* vnode_get_filesec: ???
* kauth_cred_guid2uid: ???
uid_t nuid;
gid_t ngid;
+ /*
+ * Reject attempts to fetch unknown attributes.
+ */
+ if (vap->va_active & ~VNODE_ATTR_ALL)
+ return (EINVAL);
+
/* don't ask for extended security data if the filesystem doesn't support it */
if (!vfs_extendedsecurity(vnode_mount(vp))) {
VATTR_CLEAR_ACTIVE(vap, va_acl);
int
vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
{
- int error, is_perm_change=0;
+ int error;
+#if CONFIG_FSE
+ uint64_t active;
+ int is_perm_change = 0;
+ int is_stat_change = 0;
+#endif
+
+ /*
+ * Reject attempts to set unknown attributes.
+ */
+ if (vap->va_active & ~VNODE_ATTR_ALL)
+ return (EINVAL);
/*
* Make sure the filesystem is mounted R/W.
goto out;
}
+#if DEVELOPMENT || DEBUG
+ /*
+ * XXX VSWAP: Check for entitlements or special flag here
+ * so we can restrict access appropriately.
+ */
+#else /* DEVELOPMENT || DEBUG */
+
+ if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
+ error = EPERM;
+ goto out;
+ }
+#endif /* DEVELOPMENT || DEBUG */
+
#if NAMEDSTREAMS
/* For streams, va_data_size is the only setable attribute. */
if ((vp->v_flag & VISNAMEDSTREAM) && (vap->va_active != VNODE_ATTR_va_data_size)) {
VATTR_CLEAR_ACTIVE(vap, va_gid);
}
- if ( VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid)
- || VATTR_IS_ACTIVE(vap, va_mode) || VATTR_IS_ACTIVE(vap, va_acl)) {
- is_perm_change = 1;
- }
-
/*
* Make sure that extended security is enabled if we're going to try
* to set any.
vap->va_flags &= (SF_SUPPORTED | UF_SETTABLE);
}
+#if CONFIG_FSE
+ /*
+ * Remember all of the active attributes that we're
+ * attempting to modify.
+ */
+ active = vap->va_active & ~VNODE_ATTR_RDONLY;
+#endif
+
error = VNOP_SETATTR(vp, vap, ctx);
if ((error == 0) && !VATTR_ALL_SUPPORTED(vap))
error = vnode_setattr_fallback(vp, vap, ctx);
#if CONFIG_FSE
- // only send a stat_changed event if this is more than
- // just an access or backup time update
- if (error == 0 && (vap->va_active != VNODE_ATTR_BIT(va_access_time)) && (vap->va_active != VNODE_ATTR_BIT(va_backup_time))) {
+#define PERMISSION_BITS (VNODE_ATTR_BIT(va_uid) | VNODE_ATTR_BIT(va_uuuid) | \
+ VNODE_ATTR_BIT(va_gid) | VNODE_ATTR_BIT(va_guuid) | \
+ VNODE_ATTR_BIT(va_mode) | VNODE_ATTR_BIT(va_acl))
+
+ /*
+ * Now that we've changed them, decide whether to send an
+ * FSevent.
+ */
+ if ((active & PERMISSION_BITS) & vap->va_supported) {
+ is_perm_change = 1;
+ } else {
+ /*
+ * We've already checked the permission bits, and we
+ * also want to filter out access time / backup time
+ * changes.
+ */
+ active &= ~(PERMISSION_BITS |
+ VNODE_ATTR_BIT(va_access_time) |
+ VNODE_ATTR_BIT(va_backup_time));
+
+ /* Anything left to notify about? */
+ if (active & vap->va_supported)
+ is_stat_change = 1;
+ }
+
+ if (error == 0) {
if (is_perm_change) {
if (need_fsevent(FSE_CHOWN, vp)) {
add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
}
- } else if(need_fsevent(FSE_STAT_CHANGED, vp)) {
+ } else if (is_stat_change && need_fsevent(FSE_STAT_CHANGED, vp)) {
add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
}
}
+#undef PERMISSION_BITS
#endif
out:
return (vp->v_knotes.slh_first != NULL);
}
+int
+vnode_getbackingvnode(vnode_t in_vp, vnode_t* out_vpp)
+{
+ if (out_vpp) {
+ *out_vpp = NULLVP;
+ }
+#if NULLFS
+ return nullfs_getbackingvnode(in_vp, out_vpp);
+#else
+#pragma unused(in_vp)
+ return ENOENT;
+#endif
+}
+
/*
* Initialize a struct vnode_attr and activate the attributes required
* by the vnode_notify() call.
* in the rename syscall. It's OK if the source file does not exist, since this
* is only for AppleDouble files.
*/
- if (xfromname != NULL) {
- MALLOC(fromnd, struct nameidata *, sizeof (struct nameidata), M_TEMP, M_WAITOK);
- NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK,
- UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx);
- fromnd->ni_dvp = fdvp;
- error = namei(fromnd);
-
- /*
- * If there was an error looking up source attribute file,
- * we'll behave as if it didn't exist.
- */
+ MALLOC(fromnd, struct nameidata *, sizeof (struct nameidata), M_TEMP, M_WAITOK);
+ NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK,
+ UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx);
+ fromnd->ni_dvp = fdvp;
+ error = namei(fromnd);
- if (error == 0) {
- if (fromnd->ni_vp) {
- /* src_attr_vp indicates need to call vnode_put / nameidone later */
- src_attr_vp = fromnd->ni_vp;
-
- if (fromnd->ni_vp->v_type != VREG) {
- src_attr_vp = NULLVP;
- vnode_put(fromnd->ni_vp);
- }
- }
- /*
- * Either we got an invalid vnode type (not a regular file) or the namei lookup
- * suppressed ENOENT as a valid error since we're renaming. Either way, we don't
- * have a vnode here, so we drop our namei buffer for the source attribute file
- */
- if (src_attr_vp == NULLVP) {
- nameidone(fromnd);
+ /*
+ * If there was an error looking up source attribute file,
+ * we'll behave as if it didn't exist.
+ */
+
+ if (error == 0) {
+ if (fromnd->ni_vp) {
+ /* src_attr_vp indicates need to call vnode_put / nameidone later */
+ src_attr_vp = fromnd->ni_vp;
+
+ if (fromnd->ni_vp->v_type != VREG) {
+ src_attr_vp = NULLVP;
+ vnode_put(fromnd->ni_vp);
}
}
+ /*
+ * Either we got an invalid vnode type (not a regular file) or the namei lookup
+ * suppressed ENOENT as a valid error since we're renaming. Either way, we don't
+ * have a vnode here, so we drop our namei buffer for the source attribute file
+ */
+ if (src_attr_vp == NULLVP) {
+ nameidone(fromnd);
+ }
}
}
#endif /* CONFIG_APPLEDOUBLE */
*/
if (_err == 0) {
_err = vnode_flags(tdvp, &tdfflags, ctx);
- if (_err == 0 && (tdfflags & SF_RESTRICTED)) {
- uint32_t fflags;
- _err = vnode_flags(*fvpp, &fflags, ctx);
- if (_err == 0 && !(fflags & SF_RESTRICTED)) {
- struct vnode_attr va;
- VATTR_INIT(&va);
- VATTR_SET(&va, va_flags, fflags | SF_RESTRICTED);
- _err = vnode_setattr(*fvpp, &va, ctx);
+ if (_err == 0) {
+ uint32_t inherit_flags = tdfflags & (UF_DATAVAULT | SF_RESTRICTED);
+ if (inherit_flags) {
+ uint32_t fflags;
+ _err = vnode_flags(*fvpp, &fflags, ctx);
+ if (_err == 0 && fflags != (fflags | inherit_flags)) {
+ struct vnode_attr va;
+ VATTR_INIT(&va);
+ VATTR_SET(&va, va_flags, fflags | inherit_flags);
+ _err = vnode_setattr(*fvpp, &va, ctx);
+ }
}
}
}
vnode_t sdvp, /* source directory vnode pointer (optional) */
mount_t mp, /* mount point of filesystem */
dir_clone_authorizer_op_t vattr_op, /* specific operation requested : setup, authorization or cleanup */
+ uint32_t flags; /* value passed in a_flags to the VNOP */
vfs_context_t ctx, /* As passed to VNOP */
void *reserved); /* Always NULL */
void *a_reserved; /* Currently unused */
_err = (*dvp->v_op[vnop_clonefile_desc.vdesc_offset])(&a);
- if (_err == 0 && *vpp)
+ if (_err == 0 && *vpp) {
DTRACE_FSINFO(clonefile, vnode_t, *vpp);
+ if (kdebug_enable)
+ kdebug_lookup(*vpp, cnp);
+ }
post_event_if_success(dvp, _err, NOTE_WRITE);