#include <sys/mount.h>
#include <sys/mount_internal.h>
#include <sys/time.h>
+#include <sys/disk.h>
#include <sys/vnode_internal.h>
#include <sys/stat.h>
#include <sys/namei.h>
#include <sys/ucred.h>
#include <sys/buf.h>
#include <sys/errno.h>
-#include <sys/malloc.h>
+#include <kern/kalloc.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
#include <sys/syslog.h>
#include <sys/kdebug.h>
#include <kern/assert.h>
-#include <kern/kalloc.h>
+#include <kern/zalloc.h>
#include <kern/task.h>
#include <kern/policy_internal.h>
struct vnode_attr * vap, vfs_context_t ctx);
#endif /* CONFIG_APPLEDOUBLE */
+extern lck_rw_t * rootvnode_rw_lock;
+
static errno_t post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp);
+static ZONE_VIEW_DEFINE(ZV_VFS_CONTEXT, "vfs_context",
+ KHEAP_ID_DEFAULT, sizeof(struct vfs_context));
+
/*
* vnode_setneedinactive
*
return (void*)mp->mnt_mntlabel;
}
+uint64_t
+vfs_mount_id(mount_t mp)
+{
+ return mp->mnt_mount_id;
+}
+
/* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */
uint64_t
vfs_flags(mount_t mp)
mount_unlock(mp);
}
+void
+vfs_setmntsystem(mount_t mp)
+{
+ mount_lock(mp);
+ mp->mnt_kern_flag |= MNTK_SYSTEM;
+ mount_unlock(mp);
+}
+
+void
+vfs_setmntsystemdata(mount_t mp)
+{
+ mount_lock(mp);
+ mp->mnt_kern_flag |= MNTK_SYSTEMDATA;
+ mount_unlock(mp);
+}
+
+void
+vfs_setmntswap(mount_t mp)
+{
+ mount_lock(mp);
+ mp->mnt_kern_flag |= (MNTK_SYSTEM | MNTK_SWAP_MOUNT);
+ mount_unlock(mp);
+}
+
void
vfs_clearextendedsecurity(mount_t mp)
{
mp->mnt_maxsymlinklen = symlen;
}
+boolean_t
+vfs_is_basesystem(mount_t mp)
+{
+ return ((mp->mnt_supl_kern_flag & MNTK_SUPL_BASESYSTEM) == 0) ? false : true;
+}
+
/* return a pointer to the RO vfs_statfs associated with mount_t */
struct vfsstatfs *
vfs_statfs(mount_t mp)
* the volume name
*/
if (vfs_isrdonly(mp) &&
- !((mp->mnt_flag & MNT_ROOTFS) && (vfa->f_active == VFSATTR_f_vol_name))) {
+ !((strcmp(mp->mnt_vfsstat.f_fstypename, "apfs") == 0) && (vfa->f_active == VFSATTR_f_vol_name))) {
return EROFS;
}
return EINVAL;
}
- MALLOC(newvfstbl, void *, sizeof(struct vfstable), M_TEMP,
- M_WAITOK);
- bzero(newvfstbl, sizeof(struct vfstable));
+ newvfstbl = kheap_alloc(KHEAP_TEMP, sizeof(struct vfstable),
+ Z_WAITOK | Z_ZERO);
newvfstbl->vfc_vfsops = vfe->vfe_vfsops;
strncpy(&newvfstbl->vfc_name[0], vfe->vfe_fsname, MFSNAMELEN);
if ((vfe->vfe_flags & VFS_TBLNOTYPENUM)) {
/* XXX - shouldn't be M_TEMP */
descsize = desccount * vfs_opv_numops * sizeof(PFI);
- MALLOC(descptr, PFI *, descsize,
- M_TEMP, M_WAITOK);
- bzero(descptr, descsize);
+ descptr = kheap_alloc(KHEAP_DEFAULT, descsize, Z_WAITOK | Z_ZERO);
newvfstbl->vfc_descptr = descptr;
newvfstbl->vfc_descsize = descsize;
(*newvfstbl->vfc_vfsops->vfs_init)(&vfsc);
}
- FREE(newvfstbl, M_TEMP);
+ kheap_free(KHEAP_TEMP, newvfstbl, sizeof(struct vfstable));
return 0;
}
{
struct vfstable * vfstbl = (struct vfstable *)handle;
void *old_desc = NULL;
+ size_t descsize = 0;
errno_t err;
/* Preflight check for any mounts */
*/
if (vfstbl->vfc_descptr && vfstbl->vfc_descsize) {
old_desc = vfstbl->vfc_descptr;
+ descsize = vfstbl->vfc_descsize;
}
err = vfstable_del(vfstbl);
mount_list_unlock();
/* free the descriptor if the delete was successful */
- if (err == 0 && old_desc) {
- FREE(old_desc, M_TEMP);
+ if (err == 0) {
+ kheap_free(KHEAP_DEFAULT, old_desc, descsize);
}
return err;
return 0;
}
+boolean_t
+vfs_context_can_resolve_triggers(vfs_context_t ctx)
+{
+ proc_t proc = vfs_context_proc(ctx);
+
+ if (proc) {
+ if (proc->p_vfs_iopolicy &
+ P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
/*
* vfs_context_proc
{
vfs_context_t newcontext;
- newcontext = (vfs_context_t)kalloc(sizeof(struct vfs_context));
+ newcontext = zalloc_flags(ZV_VFS_CONTEXT, Z_WAITOK | Z_ZERO);
if (newcontext) {
kauth_cred_t safecred;
vfs_context_current(void)
{
vfs_context_t ctx = NULL;
- volatile uthread_t ut = (uthread_t)get_bsdthread_info(current_thread());
+ uthread_t ut = (uthread_t)get_bsdthread_info(current_thread());
if (ut != NULL) {
if (ut->uu_context.vc_ucred != NULL) {
* This is also used by imageboot_setup(), called early from bsd_init() after
* kernproc has been given a credential.
*
- * Note: The use of proc_thread() here is a convenience to avoid inclusion
- * of many Mach headers to do the reference directly rather than indirectly;
- * we will need to forego this convenience when we reture proc_thread().
*/
static struct vfs_context kerncontext;
vfs_context_t
vfs_context_kernel(void)
{
- if (kerncontext.vc_ucred == NOCRED) {
- kerncontext.vc_ucred = kernproc->p_ucred;
- }
- if (kerncontext.vc_thread == NULL) {
- kerncontext.vc_thread = proc_thread(kernproc);
- }
-
return &kerncontext;
}
+/*
+ * Called early in bsd_init() when kernproc sets its thread and cred context.
+ */
+void
+vfs_set_context_kernel(vfs_context_t ctx)
+{
+ kerncontext = *ctx;
+}
int
vfs_context_rele(vfs_context_t ctx)
if (IS_VALID_CRED(ctx->vc_ucred)) {
kauth_cred_unref(&ctx->vc_ucred);
}
- kfree(ctx, sizeof(struct vfs_context));
+ zfree(ZV_VFS_CONTEXT, ctx);
}
return 0;
}
{
int error;
+ lck_rw_lock_shared(rootvnode_rw_lock);
error = vnode_get(rootvnode);
+ lck_rw_unlock_shared(rootvnode_rw_lock);
if (error) {
return (vnode_t)0;
} else {
void
vnode_settag(vnode_t vp, int tag)
{
- vp->v_tag = tag;
+ /*
+ * We only assign enum values to v_tag, but add an assert to make sure we
+ * catch it in dev/debug builds if this ever change.
+ */
+ assert(tag >= SHRT_MIN && tag <= SHRT_MAX);
+ vp->v_tag = (uint16_t)tag;
}
int
return vfs_context_cwd(vfs_context_current());
}
-/* returns vnode ref to current root(chroot) directory */
-vnode_t
-current_rootdir(void)
-{
- proc_t proc = current_proc();
- struct vnode * vp;
-
- if ((vp = proc->p_fd->fd_rdir)) {
- if ((vnode_getwithref(vp))) {
- return NULL;
- }
- }
- return vp;
-}
-
/*
* Get a filesec and optional acl contents from an extended attribute.
* Function will attempt to retrive ACL, UUID, and GUID information using a
}
/* get buffer and uio */
- if (((fsec = kauth_filesec_alloc(fsec_size)) == NULL) ||
+ if (((fsec = kauth_filesec_alloc((int)fsec_size)) == NULL) ||
((fsec_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ)) == NULL) ||
uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), xsize)) {
KAUTH_DEBUG(" ERROR - could not allocate iov to read ACL");
return error;
}
+/*
+ * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
+ */
+void
+vnode_attr_handle_mnt_ignore_ownership(struct vnode_attr *vap, mount_t mp, vfs_context_t ctx)
+{
+ uid_t nuid;
+ gid_t ngid;
+
+ if (VATTR_IS_ACTIVE(vap, va_uid)) {
+ if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) {
+ nuid = vap->va_uid;
+ } else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
+ nuid = mp->mnt_fsowner;
+ if (nuid == KAUTH_UID_NONE) {
+ nuid = 99;
+ }
+ } else if (VATTR_IS_SUPPORTED(vap, va_uid)) {
+ nuid = vap->va_uid;
+ } else {
+ /* this will always be something sensible */
+ nuid = mp->mnt_fsowner;
+ }
+ if ((nuid == 99) && !vfs_context_issuser(ctx)) {
+ nuid = kauth_cred_getuid(vfs_context_ucred(ctx));
+ }
+ VATTR_RETURN(vap, va_uid, nuid);
+ }
+ if (VATTR_IS_ACTIVE(vap, va_gid)) {
+ if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) {
+ ngid = vap->va_gid;
+ } else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
+ ngid = mp->mnt_fsgroup;
+ if (ngid == KAUTH_GID_NONE) {
+ ngid = 99;
+ }
+ } else if (VATTR_IS_SUPPORTED(vap, va_gid)) {
+ ngid = vap->va_gid;
+ } else {
+ /* this will always be something sensible */
+ ngid = mp->mnt_fsgroup;
+ }
+ if ((ngid == 99) && !vfs_context_issuser(ctx)) {
+ ngid = kauth_cred_getgid(vfs_context_ucred(ctx));
+ }
+ VATTR_RETURN(vap, va_gid, ngid);
+ }
+}
/*
* Returns: 0 Success
kauth_filesec_t fsec;
kauth_acl_t facl;
int error;
- uid_t nuid;
- gid_t ngid;
/*
* Reject attempts to fetch unknown attributes.
}
#endif
- /*
- * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
- */
- if (VATTR_IS_ACTIVE(vap, va_uid)) {
- if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) {
- nuid = vap->va_uid;
- } else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
- nuid = vp->v_mount->mnt_fsowner;
- if (nuid == KAUTH_UID_NONE) {
- nuid = 99;
- }
- } else if (VATTR_IS_SUPPORTED(vap, va_uid)) {
- nuid = vap->va_uid;
- } else {
- /* this will always be something sensible */
- nuid = vp->v_mount->mnt_fsowner;
- }
- if ((nuid == 99) && !vfs_context_issuser(ctx)) {
- nuid = kauth_cred_getuid(vfs_context_ucred(ctx));
- }
- VATTR_RETURN(vap, va_uid, nuid);
- }
- if (VATTR_IS_ACTIVE(vap, va_gid)) {
- if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) {
- ngid = vap->va_gid;
- } else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
- ngid = vp->v_mount->mnt_fsgroup;
- if (ngid == KAUTH_GID_NONE) {
- ngid = 99;
- }
- } else if (VATTR_IS_SUPPORTED(vap, va_gid)) {
- ngid = vap->va_gid;
- } else {
- /* this will always be something sensible */
- ngid = vp->v_mount->mnt_fsgroup;
- }
- if ((ngid == 99) && !vfs_context_issuser(ctx)) {
- ngid = kauth_cred_getgid(vfs_context_ucred(ctx));
- }
- VATTR_RETURN(vap, va_gid, ngid);
- }
+ vnode_attr_handle_mnt_ignore_ownership(vap, vp->v_mount, ctx);
/*
* Synthesise some values that can be reasonably guessed.
*/
if (!VATTR_IS_SUPPORTED(vap, va_iosize)) {
- VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize);
+ assert(vp->v_mount->mnt_vfsstat.f_iosize <= UINT32_MAX);
+ VATTR_RETURN(vap, va_iosize, (uint32_t)vp->v_mount->mnt_vfsstat.f_iosize);
}
if (!VATTR_IS_SUPPORTED(vap, va_flags)) {
}
}
+ if ((command == DKIOCISSOLIDSTATE) && (vp == rootvp) && rootvp_is_ssd && data) {
+ *data = 1;
+ return 0;
+ }
+
a.a_desc = &vnop_ioctl_desc;
a.a_vp = vp;
a.a_command = command;
* source has a "._" prefix.
*/
+ size_t xfromname_len = 0;
+ size_t xtoname_len = 0;
if (!NATIVE_XATTR(fdvp) &&
!(fcnp->cn_nameptr[0] == '.' && fcnp->cn_nameptr[1] == '_')) {
- size_t len;
int error;
/* Get source attribute file name. */
- len = fcnp->cn_namelen + 3;
- if (len > sizeof(smallname1)) {
- MALLOC(xfromname, char *, len, M_TEMP, M_WAITOK);
+ xfromname_len = fcnp->cn_namelen + 3;
+ if (xfromname_len > sizeof(smallname1)) {
+ xfromname = kheap_alloc(KHEAP_TEMP, xfromname_len, Z_WAITOK);
} else {
xfromname = &smallname1[0];
}
- strlcpy(xfromname, "._", len);
- strlcat(xfromname, fcnp->cn_nameptr, len);
+ strlcpy(xfromname, "._", xfromname_len);
+ strlcat(xfromname, fcnp->cn_nameptr, xfromname_len);
/* Get destination attribute file name. */
- len = tcnp->cn_namelen + 3;
- if (len > sizeof(smallname2)) {
- MALLOC(xtoname, char *, len, M_TEMP, M_WAITOK);
+ xtoname_len = tcnp->cn_namelen + 3;
+ if (xtoname_len > sizeof(smallname2)) {
+ xtoname = kheap_alloc(KHEAP_TEMP, xtoname_len, Z_WAITOK);
} else {
xtoname = &smallname2[0];
}
- strlcpy(xtoname, "._", len);
- strlcat(xtoname, tcnp->cn_nameptr, len);
+ strlcpy(xtoname, "._", xtoname_len);
+ strlcat(xtoname, tcnp->cn_nameptr, xtoname_len);
/*
* Look up source attribute file, keep reference on it if exists.
* in the rename syscall. It's OK if the source file does not exist, since this
* is only for AppleDouble files.
*/
- MALLOC(fromnd, struct nameidata *, sizeof(struct nameidata), M_TEMP, M_WAITOK);
+ fromnd = kheap_alloc(KHEAP_TEMP, sizeof(struct nameidata), Z_WAITOK);
NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK,
UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx);
fromnd->ni_dvp = fdvp;
* Note that tdvp already has an iocount reference. Make sure to check that we
* get a valid vnode from namei.
*/
- MALLOC(tond, struct nameidata *, sizeof(struct nameidata), M_TEMP, M_WAITOK);
+ tond = kheap_alloc(KHEAP_TEMP, sizeof(struct nameidata), Z_WAITOK);
NDINIT(tond, RENAME, OP_RENAME,
NOCACHE | NOFOLLOW | USEDVP | CN_NBMOUNTLOOK, UIO_SYSSPACE,
CAST_USER_ADDR_T(xtoname), ctx);
nameidone(tond);
}
if (xfromname && xfromname != &smallname1[0]) {
- FREE(xfromname, M_TEMP);
+ kheap_free(KHEAP_TEMP, xfromname, xfromname_len);
}
if (xtoname && xtoname != &smallname2[0]) {
- FREE(xtoname, M_TEMP);
+ kheap_free(KHEAP_TEMP, xtoname, xtoname_len);
}
#endif /* CONFIG_APPLEDOUBLE */
- if (fromnd) {
- FREE(fromnd, M_TEMP);
- }
- if (tond) {
- FREE(tond, M_TEMP);
- }
+ kheap_free(KHEAP_TEMP, fromnd, sizeof(struct nameidata));
+ kheap_free(KHEAP_TEMP, tond, sizeof(struct nameidata));
return _err;
}
struct nameidata nd;
char smallname[64];
char *filename = NULL;
- size_t len;
+ size_t alloc_len;
+ size_t copy_len;
if ((basename == NULL) || (basename[0] == '\0') ||
(basename[0] == '.' && basename[1] == '_')) {
return;
}
filename = &smallname[0];
- len = snprintf(filename, sizeof(smallname), "._%s", basename);
- if (len >= sizeof(smallname)) {
- len++; /* snprintf result doesn't include '\0' */
- MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
- len = snprintf(filename, len, "._%s", basename);
+ alloc_len = snprintf(filename, sizeof(smallname), "._%s", basename);
+ if (alloc_len >= sizeof(smallname)) {
+ alloc_len++; /* snprintf result doesn't include '\0' */
+ filename = kheap_alloc(KHEAP_TEMP, alloc_len, Z_WAITOK);
+ copy_len = snprintf(filename, alloc_len, "._%s", basename);
}
NDINIT(&nd, DELETE, OP_UNLINK, WANTPARENT | LOCKLEAF | NOFOLLOW | USEDVP, UIO_SYSSPACE,
CAST_USER_ADDR_T(filename), ctx);
vnode_put(xvp);
out2:
if (filename && filename != &smallname[0]) {
- FREE(filename, M_TEMP);
+ kheap_free(KHEAP_TEMP, filename, alloc_len);
}
}
len = snprintf(filename, sizeof(smallname), "._%s", basename);
if (len >= sizeof(smallname)) {
len++; /* snprintf result doesn't include '\0' */
- MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
+ filename = kheap_alloc(KHEAP_TEMP, len, Z_WAITOK);
len = snprintf(filename, len, "._%s", basename);
}
NDINIT(&nd, LOOKUP, OP_SETATTR, NOFOLLOW | USEDVP, UIO_SYSSPACE,
vnode_put(xvp);
out2:
if (filename && filename != &smallname[0]) {
- FREE(filename, M_TEMP);
+ kheap_free(KHEAP_TEMP, filename, len);
}
}
#endif /* CONFIG_APPLEDOUBLE */
return _err;
}
+#if 0
+/*
+*#
+*#% ap vp L L L
+*#
+*/
+struct vnop_verify_args {
+ struct vnodeop_desc *a_desc;
+ vnode_t a_vp;
+ off_t a_foffset;
+ char *a_buf;
+ size_t a_bufsize;
+ size_t *a_verifyblksize;
+ int a_flags;
+ vfs_context_t a_context;
+};
+#endif
+
+errno_t
+VNOP_VERIFY(struct vnode *vp, off_t foffset, uint8_t *buf, size_t bufsize,
+ size_t *verify_block_size, vnode_verify_flags_t flags, vfs_context_t ctx)
+{
+ int _err;
+ struct vnop_verify_args a;
+
+ if (ctx == NULL) {
+ ctx = vfs_context_current();
+ }
+ a.a_desc = &vnop_verify_desc;
+ a.a_vp = vp;
+ a.a_foffset = foffset;
+ a.a_buf = buf;
+ a.a_bufsize = bufsize;
+ a.a_verifyblksize = verify_block_size;
+ a.a_flags = flags;
+ a.a_context = ctx;
+
+ _err = (*vp->v_op[vnop_verify_desc.vdesc_offset])(&a);
+ DTRACE_FSINFO(verify, vnode_t, vp);
+
+ /* It is not an error for a filesystem to not support this VNOP */
+ if (_err == ENOTSUP) {
+ if (!buf && verify_block_size) {
+ *verify_block_size = 0;
+ }
+
+ _err = 0;
+ }
+
+ return _err;
+}
+
#if 0
/*
*#