X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/eb6b6ca394357805f2bdba989abae309f718b4d8..f427ee49d309d8fc33ebf3042c3a775f2f530ded:/bsd/vfs/vfs_attrlist.c diff --git a/bsd/vfs/vfs_attrlist.c b/bsd/vfs/vfs_attrlist.c index d7ba26600..c0bc4c89e 100644 --- a/bsd/vfs/vfs_attrlist.c +++ b/bsd/vfs/vfs_attrlist.c @@ -44,12 +44,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include #include #include @@ -59,6 +59,22 @@ #define ATTR_TIME_SIZE -1 +static int readdirattr(vnode_t, struct fd_vn_data *, uio_t, struct attrlist *, + uint64_t, int *, int *, vfs_context_t ctx) __attribute__((noinline)); + +static void +vattr_get_alt_data(vnode_t, struct attrlist *, struct vnode_attr *, int, int, + int, vfs_context_t) __attribute__((noinline)); + +static void get_error_attributes(vnode_t, struct attrlist *, uint64_t, user_addr_t, + size_t, int, caddr_t, vfs_context_t) __attribute__((noinline)); + +static int getvolattrlist(vfs_context_t, vnode_t, struct attrlist *, user_addr_t, + size_t, uint64_t, enum uio_seg, int) __attribute__((noinline)); + +static int get_direntry(vfs_context_t, vnode_t, struct fd_vn_data *, int *, + struct direntry **) __attribute__((noinline)); + /* * Structure describing the state of an in-progress attrlist operation. */ @@ -130,8 +146,8 @@ attrlist_pack_variable2(struct _attrlist_buf *ab, const void *source, ssize_t co * Note that we may be able to pack the fixed width attref, but not * the variable (if there's no room). */ - ar.attr_dataoffset = ab->varcursor - ab->fixedcursor; - ar.attr_length = count + extcount; + ar.attr_dataoffset = (int32_t)(ab->varcursor - ab->fixedcursor); + ar.attr_length = (u_int32_t)(count + extcount); attrlist_pack_fixed(ab, &ar, sizeof(ar)); /* @@ -188,7 +204,7 @@ attrlist_pack_variable(struct _attrlist_buf *ab, const void *source, ssize_t cou * allocated buffer space. */ static void -attrlist_pack_string(struct _attrlist_buf *ab, const char *source, ssize_t count) +attrlist_pack_string(struct _attrlist_buf *ab, const char *source, size_t count) { struct attrreference ar; ssize_t fit, space; @@ -206,8 +222,8 @@ attrlist_pack_string(struct _attrlist_buf *ab, const char *source, ssize_t count /* * Construct the fixed-width attribute that refers to this string. */ - ar.attr_dataoffset = ab->varcursor - ab->fixedcursor; - ar.attr_length = count + 1; + ar.attr_dataoffset = (int32_t)(ab->varcursor - ab->fixedcursor); + ar.attr_length = (u_int32_t)count + 1; attrlist_pack_fixed(ab, &ar, sizeof(ar)); /* @@ -224,7 +240,7 @@ attrlist_pack_string(struct _attrlist_buf *ab, const char *source, ssize_t count space = ab->allocated - (ab->varcursor - ab->base); fit = lmin(count, space); if (space > 0) { - int bytes_to_zero; + long bytes_to_zero; /* * If there is space remaining, copy data in, and @@ -246,7 +262,7 @@ attrlist_pack_string(struct _attrlist_buf *ab, const char *source, ssize_t count * Zero out any additional bytes we might have as a * result of rounding up. */ - bytes_to_zero = min((roundup(fit, 4) - fit), + bytes_to_zero = lmin((roundup(fit, 4) - fit), space - fit); if (bytes_to_zero) { bzero(&(ab->varcursor[fit]), bytes_to_zero); @@ -288,7 +304,7 @@ attrlist_pack_string(struct _attrlist_buf *ab, const char *source, ssize_t count struct user64_timespec us = {.tv_sec = v.tv_sec, .tv_nsec = v.tv_nsec}; \ ATTR_PACK(&b, us); \ } else { \ - struct user32_timespec us = {.tv_sec = v.tv_sec, .tv_nsec = v.tv_nsec}; \ + struct user32_timespec us = {.tv_sec = (user32_time_t)v.tv_sec, .tv_nsec = (user32_long_t)v.tv_nsec}; \ ATTR_PACK(&b, us); \ } \ } while(0) @@ -547,6 +563,7 @@ static struct getattrlist_attrtab getattrlist_common_extended_tab[] = { {.attr = ATTR_CMNEXT_REALFSID, .bits = VATTR_BIT(va_fsid64), .size = sizeof(fsid_t), .action = KAUTH_VNODE_READ_ATTRIBUTES}, {.attr = ATTR_CMNEXT_CLONEID, .bits = VATTR_BIT(va_clone_id), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES}, {.attr = ATTR_CMNEXT_EXT_FLAGS, .bits = VATTR_BIT(va_extflags), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES}, + {.attr = ATTR_CMNEXT_RECURSIVE_GENCOUNT, .bits = VATTR_BIT(va_recursive_gencount), .size = sizeof(uint64_t), .action = KAUTH_VNODE_READ_ATTRIBUTES}, {.attr = 0, .bits = 0, .size = 0, .action = 0} }; @@ -981,12 +998,7 @@ getvolattrlist(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, if (vs.f_active != 0) { /* If we're going to ask for f_vol_name, allocate a buffer to point it at */ if (VFSATTR_IS_ACTIVE(&vs, f_vol_name)) { - vs.f_vol_name = (char *) kalloc(MAXPATHLEN); - if (vs.f_vol_name == NULL) { - error = ENOMEM; - VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate f_vol_name buffer"); - goto out; - } + vs.f_vol_name = (char *) zalloc(ZV_NAMEI); vs.f_vol_name[0] = '\0'; } @@ -1193,7 +1205,7 @@ getvolattrlist(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, goto out; } - MALLOC(ab.base, char *, ab.allocated, M_TEMP, M_ZERO | M_WAITOK); + ab.base = kheap_alloc(KHEAP_TEMP, ab.allocated, Z_ZERO | Z_WAITOK); if (ab.base == NULL) { error = ENOMEM; VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate %d for copy buffer", ab.allocated); @@ -1485,6 +1497,14 @@ getvolattrlist(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, vs.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] |= VOL_CAP_FMT_NO_PERMISSIONS; } + /* + * ATTR_CMN_USERACCESS attribute was previously set by file-system drivers, thus volume capabilitiy + * VOL_CAP_INT_USERACCESS was conditionally enabled. ATTR_CMN_USERACCESS is now set inside VFS, + * regardless of underlying volume type thus we always set VOL_CAP_INT_USERACCESS. + */ + vs.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_USERACCESS; + vs.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_USERACCESS; + ATTR_PACK(&ab, vs.f_capabilities); ab.actual.volattr |= ATTR_VOL_CAPABILITIES; } @@ -1533,7 +1553,7 @@ getvolattrlist(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, * of the result buffer, even if we copied less out. The caller knows how big a buffer * they gave us, so they can always check for truncation themselves. */ - *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? ab.needed : imin(bufferSize, ab.needed); + *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? (uint32_t)ab.needed : (uint32_t)lmin(bufferSize, ab.needed); /* Return attribute set output if requested. */ if (return_valid && @@ -1549,21 +1569,19 @@ getvolattrlist(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, if (UIO_SEG_IS_USER_SPACE(segflg)) { error = copyout(ab.base, CAST_USER_ADDR_T(attributeBuffer), - ulmin(bufferSize, ab.needed)); + ulmin((uint32_t)bufferSize, (uint32_t)ab.needed)); } else { - bcopy(ab.base, (void *)attributeBuffer, (size_t)ulmin(bufferSize, ab.needed)); + bcopy(ab.base, (void *)attributeBuffer, (size_t)ulmin((uint32_t)bufferSize, (uint32_t)ab.needed)); } out: if (vs.f_vol_name != NULL) { - kfree(vs.f_vol_name, MAXPATHLEN); + zfree(ZV_NAMEI, vs.f_vol_name); } if (release_str) { vnode_putname(cnp); } - if (ab.base != NULL) { - FREE(ab.base, M_TEMP); - } + kheap_free(KHEAP_TEMP, ab.base, ab.allocated); VFS_DEBUG(ctx, vp, "ATTRLIST - returning %d", error); if (root_vp != NULL) { @@ -2381,6 +2399,16 @@ attr_pack_common_extended(mount_t mp, struct vnode *vp, struct attrlist *alp, } } + if (alp->forkattr & ATTR_CMNEXT_RECURSIVE_GENCOUNT) { + if (VATTR_IS_SUPPORTED(vap, va_recursive_gencount)) { + ATTR_PACK8((*abp), vap->va_recursive_gencount); + abp->actual.forkattr |= ATTR_CMNEXT_RECURSIVE_GENCOUNT; + } else if (!return_valid || pack_invalid) { + uint64_t zero_val = 0; + ATTR_PACK8((*abp), zero_val); + } + } + return 0; } @@ -2737,13 +2765,7 @@ vfs_attr_pack_internal(mount_t mp, vnode_t vp, uio_t auio, struct attrlist *alp, //if a path is requested, allocate a temporary buffer to build it if (vp && (alp->commonattr & (ATTR_CMN_FULLPATH))) { - fullpathptr = (char*) kalloc(MAXPATHLEN); - if (fullpathptr == NULL) { - error = ENOMEM; - VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: cannot allocate fullpath buffer"); - goto out; - } - bzero(fullpathptr, MAXPATHLEN); + fullpathptr = (char*) zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO); apaths.fullpathptr = fullpathptr; apaths.fullpathlenp = &fullpathlen; } @@ -2751,25 +2773,13 @@ vfs_attr_pack_internal(mount_t mp, vnode_t vp, uio_t auio, struct attrlist *alp, // only interpret fork attributes if they're used as new common attributes if (vp && use_fork) { if (alp->forkattr & (ATTR_CMNEXT_RELPATH)) { - relpathptr = (char*) kalloc(MAXPATHLEN); - if (relpathptr == NULL) { - error = ENOMEM; - VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: cannot allocate relpath buffer"); - goto out; - } - bzero(relpathptr, MAXPATHLEN); + relpathptr = (char*) zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO); apaths.relpathptr = relpathptr; apaths.relpathlenp = &relpathlen; } if (alp->forkattr & (ATTR_CMNEXT_NOFIRMLINKPATH)) { - REALpathptr = (char*) kalloc(MAXPATHLEN); - if (REALpathptr == NULL) { - error = ENOMEM; - VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: cannot allocate canonpath buffer"); - goto out; - } - bzero(REALpathptr, MAXPATHLEN); + REALpathptr = (char*) zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO); apaths.REALpathptr = REALpathptr; apaths.REALpathlenp = &REALpathlen; } @@ -2821,8 +2831,7 @@ vfs_attr_pack_internal(mount_t mp, vnode_t vp, uio_t auio, struct attrlist *alp, * and big enough. */ if (uio_isuserspace(auio) || (buf_size < ab.allocated)) { - MALLOC(ab.base, char *, ab.allocated, M_TEMP, - M_ZERO | M_WAITOK); + ab.base = kheap_alloc(KHEAP_TEMP, ab.allocated, Z_ZERO | Z_WAITOK); alloc_local_buf = 1; } else { /* @@ -2937,7 +2946,7 @@ vfs_attr_pack_internal(mount_t mp, vnode_t vp, uio_t auio, struct attrlist *alp, * of the result buffer, even if we copied less out. The caller knows how big a buffer * they gave us, so they can always check for truncation themselves. */ - *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? ab.needed : imin(ab.allocated, ab.needed); + *(uint32_t *)ab.base = (options & FSOPT_REPORT_FULLSIZE) ? (uint32_t)ab.needed : (uint32_t)lmin(ab.allocated, ab.needed); /* Return attribute set output if requested. */ if (return_valid) { @@ -2951,11 +2960,11 @@ vfs_attr_pack_internal(mount_t mp, vnode_t vp, uio_t auio, struct attrlist *alp, bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof(ab.actual)); } - copy_size = imin(buf_size, ab.allocated); + copy_size = lmin(buf_size, ab.allocated); /* Only actually copyout as much out as the user buffer can hold */ if (alloc_local_buf) { - error = uiomove(ab.base, copy_size, auio); + error = uiomove(ab.base, (int)copy_size, auio); } else { off_t orig_offset = uio_offset(auio); @@ -2980,16 +2989,16 @@ out: vnode_putname(vname); } if (fullpathptr) { - kfree(fullpathptr, MAXPATHLEN); + zfree(ZV_NAMEI, fullpathptr); } if (relpathptr) { - kfree(relpathptr, MAXPATHLEN); + zfree(ZV_NAMEI, relpathptr); } if (REALpathptr) { - kfree(REALpathptr, MAXPATHLEN); + zfree(ZV_NAMEI, REALpathptr); } - if (ab.base != NULL && alloc_local_buf) { - FREE(ab.base, M_TEMP); + if (alloc_local_buf) { + kheap_free(KHEAP_TEMP, ab.base, ab.allocated); } return error; } @@ -3055,7 +3064,7 @@ 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* authoritative_name, struct ucred *file_cred) { - struct vnode_attr va; + struct vnode_attr *va; kauth_action_t action; ssize_t fixedsize; char *va_name; @@ -3086,7 +3095,8 @@ getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, &uio_buf[0], sizeof(uio_buf)); uio_addiov(auio, attributeBuffer, bufferSize); - VATTR_INIT(&va); + va = kheap_alloc(KHEAP_TEMP, sizeof(struct vnode_attr), Z_WAITOK); + VATTR_INIT(va); va_name = NULL; if (alp->bitmapcount != ATTR_BIT_MAP_COUNT) { @@ -3156,7 +3166,7 @@ getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, goto out; } /* Keep invalid attrs from being uninitialized */ - bzero(&va, sizeof(va)); + bzero(va, sizeof(*va)); } /* Pick up the vnode type. If the FS is bad and changes vnode types on us, we @@ -3167,7 +3177,7 @@ getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, /* * Set up the vnode_attr structure and authorise. */ - if ((error = getattrlist_setupvattr(alp, &va, &fixedsize, &action, proc_is64, (vtype == VDIR), use_fork)) != 0) { + if ((error = getattrlist_setupvattr(alp, va, &fixedsize, &action, proc_is64, (vtype == VDIR), use_fork)) != 0) { VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: setup for request failed"); goto out; } @@ -3177,20 +3187,14 @@ getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, } - if (va.va_active != 0) { - uint64_t va_active = va.va_active; + if (va->va_active != 0) { + uint64_t va_active = va->va_active; /* * If we're going to ask for va_name, allocate a buffer to point it at */ - if (VATTR_IS_ACTIVE(&va, va_name)) { - MALLOC_ZONE(va_name, char *, MAXPATHLEN, M_NAMEI, - M_WAITOK); - if (va_name == NULL) { - error = ENOMEM; - VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: cannot allocate va_name buffer"); - goto out; - } + if (VATTR_IS_ACTIVE(va, va_name)) { + va_name = zalloc(ZV_NAMEI); /* * If we have an authoritative_name, prefer that name. * @@ -3201,21 +3205,21 @@ getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, */ if (authoritative_name) { /* Don't ask the file system */ - VATTR_CLEAR_ACTIVE(&va, va_name); + VATTR_CLEAR_ACTIVE(va, va_name); strlcpy(va_name, authoritative_name, MAXPATHLEN); } } - va.va_name = authoritative_name ? NULL : va_name; + va->va_name = authoritative_name ? NULL : va_name; if (options & FSOPT_RETURN_REALDEV) { - va.va_vaflags |= VA_REALFSID; + va->va_vaflags |= VA_REALFSID; } /* * Call the filesystem. */ - if ((error = vnode_getattr(vp, &va, ctx)) != 0) { + if ((error = vnode_getattr(vp, va, ctx)) != 0) { VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: filesystem returned %d", error); goto out; } @@ -3230,7 +3234,7 @@ getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, * opportunity to change the values of attributes * retrieved. */ - error = mac_vnode_check_getattr(ctx, file_cred, vp, &va); + error = mac_vnode_check_getattr(ctx, file_cred, vp, va); if (error) { VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: MAC framework returned %d", error); goto out; @@ -3247,26 +3251,27 @@ getattrlist_internal(vfs_context_t ctx, vnode_t vp, struct attrlist *alp, * A (buggy) filesystem may change fields which belong * to us. We try to deal with that here as well. */ - va.va_active = va_active; + va->va_active = va_active; if (authoritative_name && va_name) { - VATTR_SET_ACTIVE(&va, va_name); - if (!(VATTR_IS_SUPPORTED(&va, va_name))) { - VATTR_SET_SUPPORTED(&va, 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; + va->va_name = va_name; } - error = vfs_attr_pack_internal(vp->v_mount, vp, auio, alp, options, &va, NULL, ctx, + error = vfs_attr_pack_internal(vp->v_mount, vp, auio, alp, options, va, NULL, ctx, 0, vtype, fixedsize); out: if (va_name) { - FREE_ZONE(va_name, MAXPATHLEN, M_NAMEI); + zfree(ZV_NAMEI, va_name); } - if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) { - kauth_acl_free(va.va_acl); + if (VATTR_IS_SUPPORTED(va, va_acl) && (va->va_acl != NULL)) { + kauth_acl_free(va->va_acl); } + kheap_free(KHEAP_TEMP, va, sizeof(struct vnode_attr)); VFS_DEBUG(ctx, vp, "ATTRLIST - returning %d", error); return error; @@ -3286,13 +3291,12 @@ fgetattrlist(proc_t p, struct fgetattrlist_args *uap, __unused int32_t *retval) fp = NULL; error = 0; - if ((error = file_vnode(uap->fd, &vp)) != 0) { + if ((error = fp_get_ftype(p, uap->fd, DTYPE_VNODE, EINVAL, &fp)) != 0) { return error; } + vp = (struct vnode *)fp->fp_glob->fg_data; - if ((error = fp_lookup(p, uap->fd, &fp, 0)) != 0 || - (error = vnode_getwithref(vp)) != 0) { - vp = NULL; + if ((error = vnode_getwithref(vp)) != 0) { goto out; } @@ -3301,7 +3305,7 @@ fgetattrlist(proc_t p, struct fgetattrlist_args *uap, __unused int32_t *retval) */ error = copyin(uap->alist, &al, sizeof(al)); if (error) { - goto out; + goto out_vnode_put; } /* Default to using the vnode's name. */ @@ -3309,16 +3313,12 @@ fgetattrlist(proc_t p, struct fgetattrlist_args *uap, __unused int32_t *retval) uap->bufferSize, uap->options, (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : \ UIO_USERSPACE32), NULL, - fp->f_fglob->fg_cred); + fp->fp_glob->fg_cred); +out_vnode_put: + vnode_put(vp); out: - if (fp) { - fp_drop(p, uap->fd, fp, 0); - } - if (vp) { - vnode_put(vp); - } - file_drop(uap->fd); + fp_drop(p, uap->fd, fp, 0); return error; } @@ -3438,7 +3438,7 @@ refill_fd_direntries(vfs_context_t ctx, vnode_t dvp, struct fd_vn_data *fvd, if (fvd->fv_eofflag) { *eofflagp = 1; if (fvd->fv_buf) { - FREE(fvd->fv_buf, M_FD_DIRBUF); + kheap_free(KHEAP_DATA_BUFFERS, fvd->fv_buf, fvd->fv_bufallocsiz); fvd->fv_buf = NULL; } return 0; @@ -3470,7 +3470,8 @@ retry_alloc: * not copied out to user space. */ if (!fvd->fv_buf) { - MALLOC(fvd->fv_buf, caddr_t, rdirbufsiz, M_FD_DIRBUF, M_WAITOK); + fvd->fv_buf = kheap_alloc(KHEAP_DATA_BUFFERS, rdirbufsiz, Z_WAITOK); + fvd->fv_bufallocsiz = rdirbufsiz; fvd->fv_bufdone = 0; } @@ -3498,8 +3499,6 @@ retry_alloc: fvd->fv_bufsiz = rdirbufused; fvd->fv_bufdone = 0; bzero(fvd->fv_buf + rdirbufused, rdirbufsiz - rdirbufused); - /* Cache allocation size the Filesystem responded to */ - fvd->fv_bufallocsiz = rdirbufsiz; } else if (!eofflag && (rdirbufsiz < FV_DIRBUF_MAX_SIZ)) { /* * Some Filesystems have higher requirements for the @@ -3511,8 +3510,7 @@ retry_alloc: * from VNOP_READDIR is ignored until at least FV_DIRBUF_MAX_SIZ * has been attempted. */ - FREE(fvd->fv_buf, M_FD_DIRBUF); - fvd->fv_buf = NULL; + kheap_free(KHEAP_DATA_BUFFERS, fvd->fv_buf, fvd->fv_bufallocsiz); rdirbufsiz = 2 * rdirbufsiz; fvd->fv_bufallocsiz = 0; goto retry_alloc; @@ -3539,8 +3537,10 @@ retry_alloc: * time to free up directory entry buffer. */ if ((error || eofflag) && fvd->fv_buf) { - FREE(fvd->fv_buf, M_FD_DIRBUF); - fvd->fv_buf = NULL; + kheap_free(KHEAP_DATA_BUFFERS, fvd->fv_buf, fvd->fv_bufallocsiz); + if (error) { + fvd->fv_bufallocsiz = 0; + } } *eofflagp = eofflag; @@ -3642,7 +3642,7 @@ get_error_attributes(vnode_t vp, struct attrlist *alp, uint64_t options, { size_t fsiz, vsiz; struct _attrlist_buf ab; - int namelen; + size_t namelen; kauth_action_t action; struct attrlist al; int needs_error_attr = (alp->commonattr & ATTR_CMN_ERROR); @@ -3689,7 +3689,7 @@ get_error_attributes(vnode_t vp, struct attrlist *alp, uint64_t options, ab.needed = fsiz + vsiz; /* Fill in the size needed */ - *((uint32_t *)ab.base) = ab.needed; + *((uint32_t *)ab.base) = (uint32_t)ab.needed; if (ab.needed > (ssize_t)kern_attr_buf_siz) { goto out; } @@ -3784,7 +3784,7 @@ readdirattr(vnode_t dvp, struct fd_vn_data *fvd, uio_t auio, return error; } - MALLOC(kern_attr_buf, caddr_t, kern_attr_buf_siz, M_TEMP, M_WAITOK); + kern_attr_buf = kheap_alloc(KHEAP_TEMP, kern_attr_buf_siz, Z_WAITOK); while (uio_resid(auio) > (user_ssize_t)MIN_BUF_SIZE_REQUIRED) { struct direntry *dp; @@ -3823,8 +3823,7 @@ readdirattr(vnode_t dvp, struct fd_vn_data *fvd, uio_t auio, */ if (dp->d_name[dp->d_namlen] != '\0') { if (!max_path_name_buf) { - MALLOC(max_path_name_buf, caddr_t, MAXPATHLEN, - M_TEMP, M_WAITOK); + max_path_name_buf = zalloc_flags(ZV_NAMEI, Z_WAITOK); } bcopy(dp->d_name, max_path_name_buf, dp->d_namlen); max_path_name_buf[dp->d_namlen] = '\0'; @@ -3937,7 +3936,7 @@ readdirattr(vnode_t dvp, struct fd_vn_data *fvd, uio_t auio, entlen += pad_bytes; } *((uint32_t *)kern_attr_buf) = (uint32_t)entlen; - error = uiomove(kern_attr_buf, min(entlen, kern_attr_buf_siz), + error = uiomove(kern_attr_buf, min((int)entlen, (int)kern_attr_buf_siz), auio); if (error) { @@ -3957,13 +3956,13 @@ readdirattr(vnode_t dvp, struct fd_vn_data *fvd, uio_t auio, } if (max_path_name_buf) { - FREE(max_path_name_buf, M_TEMP); + zfree(ZV_NAMEI, max_path_name_buf); } /* * At this point, kern_attr_buf is always allocated */ - FREE(kern_attr_buf, M_TEMP); + kheap_free(KHEAP_TEMP, kern_attr_buf, kern_attr_buf_siz); /* * Always set the offset to the last succesful offset @@ -3974,6 +3973,11 @@ readdirattr(vnode_t dvp, struct fd_vn_data *fvd, uio_t auio, return error; } +/* common attributes that only require KAUTH_VNODE_LIST_DIRECTORY */ +#define LIST_DIR_ATTRS (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE | \ + ATTR_CMN_FILEID | ATTR_CMN_RETURNED_ATTRS | \ + ATTR_CMN_ERROR) + /* * int getattrlistbulk(int dirfd, struct attrlist *alist, void *attributeBuffer, * size_t bufferSize, uint64_t options) @@ -4015,7 +4019,7 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) ut = get_bsdthread_info(current_thread()); segflg = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32; - if ((fp->f_fglob->fg_flag & FREAD) == 0) { + if ((fp->fp_glob->fg_flag & FREAD) == 0) { /* * AUDIT_ARG(vnpath_withref, dvp, ARG_VNODE1); */ @@ -4053,7 +4057,7 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) #if CONFIG_MACF error = mac_file_check_change_offset(vfs_context_ucred(ctx), - fp->f_fglob); + fp->fp_glob); if (error) { goto out; } @@ -4084,12 +4088,12 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) #endif /* MAC */ /* - * If the only item requested is file names, we can let that past with - * just LIST_DIRECTORY. If they want any other attributes, that means - * they need SEARCH as well. + * Requested attributes that are available in the direntry struct, with the addition + * of ATTR_CMN_RETURNED_ATTRS and ATTR_CMN_ERROR, can be let past with just LIST_DIRECTORY. + * Any other requested attributes require SEARCH as well. */ action = KAUTH_VNODE_LIST_DIRECTORY; - if ((al.commonattr & ~ATTR_CMN_NAME) || al.fileattr || al.dirattr) { + if ((al.commonattr & ~LIST_DIR_ATTRS) || al.fileattr || al.dirattr) { action |= KAUTH_VNODE_SEARCH; } @@ -4098,7 +4102,7 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) goto out; } - fvdata = (struct fd_vn_data *)fp->f_fglob->fg_vn_data; + fvdata = (struct fd_vn_data *)fp->fp_glob->fg_vn_data; if (!fvdata) { panic("Directory expected to have fg_vn_data"); } @@ -4111,12 +4115,10 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) * traversal needs to be restarted (Any existing state in the * directory buffer is removed as well). */ - if (!fp->f_fglob->fg_offset) { + if (!fp->fp_glob->fg_offset) { fvdata->fv_offset = 0; - if (fvdata->fv_buf) { - FREE(fvdata->fv_buf, M_FD_DIRBUF); - } - fvdata->fv_buf = NULL; + kheap_free(KHEAP_DATA_BUFFERS, fvdata->fv_buf, + fvdata->fv_bufallocsiz); fvdata->fv_bufsiz = 0; fvdata->fv_bufdone = 0; fvdata->fv_soff = 0; @@ -4141,7 +4143,7 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) !(al.commonattr & ATTR_CMN_OBJTYPE)) { error = ENOTSUP; } else { - struct vnode_attr va; + struct vnode_attr *va; char *va_name; if (fvdata->fv_eofflag && !fvdata->fv_buf) { @@ -4156,12 +4158,13 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) eofflag = 0; count = 0; - VATTR_INIT(&va); - MALLOC(va_name, char *, MAXPATHLEN, M_TEMP, - M_WAITOK | M_ZERO); - va.va_name = va_name; + va = kheap_alloc(KHEAP_TEMP, sizeof(struct vnode_attr), Z_WAITOK); + + VATTR_INIT(va); + va_name = zalloc_flags(ZV_NAMEI, Z_WAITOK | Z_ZERO); + va->va_name = va_name; - (void)getattrlist_setupvattr_all(&al, &va, VNON, NULL, + (void)getattrlist_setupvattr_all(&al, va, VNON, NULL, IS_64BIT_PROCESS(p), (uap->options & FSOPT_ATTR_CMN_EXTENDED)); /* @@ -4169,11 +4172,12 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) * filesystem to be rapidly aged. */ ut->uu_flag |= UT_KERN_RAGE_VNODES; - error = VNOP_GETATTRLISTBULK(dvp, &al, &va, auio, NULL, + error = VNOP_GETATTRLISTBULK(dvp, &al, va, auio, NULL, options, &eofflag, &count, ctx); ut->uu_flag &= ~UT_KERN_RAGE_VNODES; - FREE(va_name, M_TEMP); + zfree(ZV_NAMEI, va_name); + kheap_free(KHEAP_TEMP, va, sizeof(struct vnode_attr)); /* * cache state of eofflag. @@ -4200,7 +4204,7 @@ getattrlistbulk(proc_t p, struct getattrlistbulk_args *uap, int32_t *retval) if (count) { fvdata->fv_offset = uio_offset(auio); - fp->f_fglob->fg_offset = fvdata->fv_offset; + fp->fp_glob->fg_offset = fvdata->fv_offset; *retval = count; error = 0; } else if (!error && !eofflag) { @@ -4236,14 +4240,14 @@ attrlist_unpack_fixed(char **cursor, char *end, void *buf, ssize_t size) } #define ATTR_UNPACK(v) do {if ((error = attrlist_unpack_fixed(&cursor, bufend, &v, sizeof(v))) != 0) goto out;} while(0); -#define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = _f;} while(0) +#define ATTR_UNPACK_CAST(t, v) do { t _f; ATTR_UNPACK(_f); v = (typeof(v))_f;} while(0) #define ATTR_UNPACK_TIME(v, is64) \ do { \ if (is64) { \ struct user64_timespec us; \ ATTR_UNPACK(us); \ - v.tv_sec = us.tv_sec; \ - v.tv_nsec = us.tv_nsec; \ + v.tv_sec = (unsigned long)us.tv_sec; \ + v.tv_nsec = (long)us.tv_nsec; \ } else { \ struct user32_timespec us; \ ATTR_UNPACK(us); \ @@ -4325,9 +4329,7 @@ setattrlist_internal(vnode_t vp, struct setattrlist_args *uap, proc_t p, vfs_con /* * If the caller's bitmaps indicate that there are no attributes to set, - * then exit early. In particular, we want to avoid the MALLOC below - * since the caller's bufferSize could be zero, and MALLOC of zero bytes - * returns a NULL pointer, which would cause setattrlist to return ENOMEM. + * then exit early. */ if (al.commonattr == 0 && (al.volattr & ~ATTR_VOL_INFO) == 0 && @@ -4352,7 +4354,7 @@ setattrlist_internal(vnode_t vp, struct setattrlist_args *uap, proc_t p, vfs_con error = ENOMEM; goto out; } - MALLOC(user_buf, char *, uap->bufferSize, M_TEMP, M_WAITOK); + user_buf = kheap_alloc(KHEAP_DATA_BUFFERS, uap->bufferSize, Z_WAITOK); if (user_buf == NULL) { VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: could not allocate %d bytes for buffer", uap->bufferSize); error = ENOMEM; @@ -4642,9 +4644,7 @@ setattrlist_internal(vnode_t vp, struct setattrlist_args *uap, proc_t p, vfs_con /* all done and successful */ out: - if (user_buf != NULL) { - FREE(user_buf, M_TEMP); - } + kheap_free(KHEAP_DATA_BUFFERS, user_buf, uap->bufferSize); VFS_DEBUG(ctx, vp, "ATTRLIST - set returning %d", error); return error; } @@ -4655,7 +4655,7 @@ setattrlist(proc_t p, struct setattrlist_args *uap, __unused int32_t *retval) struct vfs_context *ctx; struct nameidata nd; vnode_t vp = NULL; - u_long nameiflags; + uint32_t nameiflags; int error = 0; ctx = vfs_context_current();