/*
- * Copyright (c) 1995-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 1995-2017 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/fsevents.h>
#include <kern/kalloc.h>
#include <miscfs/specfs/specdev.h>
+#include <security/audit/audit.h>
#if CONFIG_MACF
#include <security/mac_framework.h>
#define ATTR_PACK8(AB, V) \
do { \
if ((AB.allocated - (AB.fixedcursor - AB.base)) >= 8) { \
- *(uint64_t *)AB.fixedcursor = *(uint64_t *)&V; \
+ memcpy(AB.fixedcursor, &V, 8); \
AB.fixedcursor += 8; \
} \
} while (0)
{ATTR_VOL_ENCODINGSUSED, 0, sizeof(uint64_t)},
{ATTR_VOL_CAPABILITIES, VFSATTR_BIT(f_capabilities), sizeof(vol_capabilities_attr_t)},
{ATTR_VOL_UUID, VFSATTR_BIT(f_uuid), sizeof(uuid_t)},
- {ATTR_VOL_QUOTA_SIZE, VFSATTR_BIT(f_quota), sizeof(off_t)},
- {ATTR_VOL_RESERVED_SIZE, VFSATTR_BIT(f_reserved), sizeof(off_t)},
+ {ATTR_VOL_QUOTA_SIZE, VFSATTR_BIT(f_quota) | VFSATTR_BIT(f_bsize), sizeof(off_t)},
+ {ATTR_VOL_RESERVED_SIZE, VFSATTR_BIT(f_reserved) | VFSATTR_BIT(f_bsize), sizeof(off_t)},
{ATTR_VOL_ATTRIBUTES, VFSATTR_BIT(f_attributes), sizeof(vol_attributes_attr_t)},
{ATTR_VOL_INFO, 0, 0},
{0, 0, 0}
static struct getattrlist_attrtab getattrlist_common_extended_tab[] = {
{ATTR_CMNEXT_RELPATH, 0, sizeof(struct attrreference), KAUTH_VNODE_READ_ATTRIBUTES},
{ATTR_CMNEXT_PRIVATESIZE, VATTR_BIT(va_private_size), sizeof(off_t), KAUTH_VNODE_READ_ATTRIBUTES},
+ {ATTR_CMNEXT_LINKID, VATTR_BIT(va_fileid) | VATTR_BIT(va_linkid), sizeof(uint64_t), KAUTH_VNODE_READ_ATTRIBUTES},
{0, 0, 0, 0}
};
ATTR_CMN_DOCUMENT_ID | ATTR_CMN_GEN_COUNT | \
ATTR_CMN_DATA_PROTECT_FLAGS)
-#define VFS_DFLT_ATT_CMN_EXT (ATTR_CMNEXT_PRIVATESIZE)
+#define VFS_DFLT_ATTR_CMN_EXT (ATTR_CMNEXT_PRIVATESIZE | ATTR_CMNEXT_LINKID)
#define VFS_DFLT_ATTR_DIR (ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS)
attrp->validattr.volattr = VFS_DFLT_ATTR_VOL;
attrp->validattr.dirattr = VFS_DFLT_ATTR_DIR;
attrp->validattr.fileattr = VFS_DFLT_ATTR_FILE;
- attrp->validattr.forkattr = 0;
+ attrp->validattr.forkattr = VFS_DFLT_ATTR_CMN_EXT;
attrp->nativeattr.commonattr = 0;
attrp->nativeattr.volattr = 0;
vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] &= ~VOL_CAP_INT_EXTENDED_SECURITY;
}
vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_EXTENDED_SECURITY;
+
+ /*
+ * if the filesystem doesn't mark either VOL_CAP_FMT_NO_IMMUTABLE_FILES
+ * or VOL_CAP_FMT_NO_PERMISSIONS as valid, assume they're not supported
+ */
+ if (!(vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_NO_IMMUTABLE_FILES)) {
+ vs.f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] &= ~VOL_CAP_FMT_NO_IMMUTABLE_FILES;
+ vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_NO_IMMUTABLE_FILES;
+ }
+
+ if (!(vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_NO_PERMISSIONS)) {
+ vs.f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] &= ~VOL_CAP_FMT_NO_PERMISSIONS;
+ vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_NO_PERMISSIONS;
+ }
+
ATTR_PACK(&ab, vs.f_capabilities);
ab.actual.volattr |= ATTR_VOL_CAPABILITIES;
}
}
}
+ if (alp->forkattr & ATTR_CMNEXT_LINKID) {
+ uint64_t linkid;
+
+ if (VATTR_IS_SUPPORTED(vap, va_linkid))
+ linkid = vap->va_linkid;
+ else
+ linkid = vap->va_fileid;
+
+ ATTR_PACK8((*abp), linkid);
+ abp->actual.forkattr |= ATTR_CMNEXT_LINKID;
+ }
+
return 0;
}
static int
getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp,
user_addr_t attributeBuffer, size_t bufferSize, uint64_t options,
- enum uio_seg segflg, char* alt_name, struct ucred *file_cred)
+ enum uio_seg segflg, char* authoritative_name, struct ucred *file_cred)
{
struct vnode_attr va;
kauth_action_t action;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: cannot allocate va_name buffer");
goto out;
}
+ /*
+ * If we have an authoritative_name, prefer that name.
+ *
+ * N.B. Since authoritative_name implies this is coming from getattrlistbulk,
+ * we know the name is authoritative. For /dev/fd, we want to use the file
+ * descriptor as the name not the underlying name of the associate vnode in a
+ * particular file system.
+ */
+ if (authoritative_name) {
+ /* Don't ask the file system */
+ VATTR_CLEAR_ACTIVE(&va, va_name);
+ strlcpy(va_name, authoritative_name, MAXPATHLEN);
+ }
}
- va.va_name = va_name;
+ va.va_name = authoritative_name ? NULL : va_name;
/*
* Call the filesystem.
#endif
/*
- * If ATTR_CMN_NAME is not supported by filesystem and the
- * caller has provided a name, use that.
+ * It we ask for the name, i.e., vname is non null and
+ * we have an authoritative name, then reset va_name is
+ * active and if needed set va_name is supported.
+ *
* A (buggy) filesystem may change fields which belong
* to us. We try to deal with that here as well.
*/
va.va_active = va_active;
- if (alt_name && va_name &&
- !(VATTR_IS_SUPPORTED(&va, va_name))) {
- strlcpy(va_name, alt_name, MAXPATHLEN);
- VATTR_SET_SUPPORTED(&va, va_name);
+ if (authoritative_name && va_name) {
+ VATTR_SET_ACTIVE(&va, va_name);
+ if (!(VATTR_IS_SUPPORTED(&va, va_name))) {
+ VATTR_SET_SUPPORTED(&va, va_name);
+ }
}
va.va_name = va_name;
}
if (uap->options & FSOPT_LIST_SNAPSHOT) {
vnode_t snapdvp;
- if (!vfs_context_issuser(ctx)) {
- error = EPERM;
- goto out;
- }
-
if (!vnode_isvroot(dvp)) {
error = EINVAL;
goto out;
ATTR_UNPACK(va.va_guuid);
VATTR_SET_ACTIVE(&va, va_guuid);
}
+ if (al.commonattr & ATTR_CMN_ADDEDTIME) {
+ ATTR_UNPACK_TIME(va.va_addedtime, proc_is64);
+ VATTR_SET_ACTIVE(&va, va_addedtime);
+ }
/* Support setattrlist of data protection class */
if (al.commonattr & ATTR_CMN_DATA_PROTECT_FLAGS) {
ATTR_UNPACK(va.va_dataprotect_class);
return error;
}
+int
+setattrlistat(proc_t p, struct setattrlistat_args *uap, __unused int32_t *retval)
+{
+ struct setattrlist_args ap;
+ struct vfs_context *ctx;
+ struct nameidata nd;
+ vnode_t vp = NULLVP;
+ uint32_t nameiflags;
+ int error;
+
+ ctx = vfs_context_current();
+
+ AUDIT_ARG(fd, uap->fd);
+ /*
+ * Look up the file.
+ */
+ nameiflags = AUDITVNPATH1;
+ if (!(uap->options & FSOPT_NOFOLLOW))
+ nameiflags |= FOLLOW;
+ NDINIT(&nd, LOOKUP, OP_SETATTR, nameiflags, UIO_USERSPACE, uap->path, ctx);
+ if ((error = nameiat(&nd, uap->fd)) != 0)
+ goto out;
+ vp = nd.ni_vp;
+ nameidone(&nd);
+
+ ap.path = 0;
+ ap.alist = uap->alist;
+ ap.attributeBuffer = uap->attributeBuffer;
+ ap.bufferSize = uap->bufferSize;
+ ap.options = uap->options;
+
+ error = setattrlist_internal(vp, &ap, p, ctx);
+out:
+ if (vp)
+ vnode_put(vp);
+ return (error);
+}
+
int
fsetattrlist(proc_t p, struct fsetattrlist_args *uap, __unused int32_t *retval)
{