X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/cb3231590a3c94ab4375e2228bd5e86b0cf1ad7e..c3c9b80d004dbbfdf763edeb97968c6997e3b45b:/bsd/vfs/vfs_lookup.c?ds=sidebyside diff --git a/bsd/vfs/vfs_lookup.c b/bsd/vfs/vfs_lookup.c index aaaf2fbb1..efe27e3e0 100644 --- a/bsd/vfs/vfs_lookup.c +++ b/bsd/vfs/vfs_lookup.c @@ -81,19 +81,19 @@ #include #include #include -#include +#include #include #include #include #include /* For _PC_NAME_MAX */ #include #include -#include +#include #include -#include /* to get the prototype for strstr() in sys/dtrace_glue.h */ #if CONFIG_MACF #include #endif +#include #include @@ -113,7 +113,7 @@ static int vfs_getrealpath(const char * path, char * realpath, size_t bufsize, v #endif static int lookup_traverse_mountpoints(struct nameidata *ndp, struct componentname *cnp, vnode_t dp, int vbusyflags, vfs_context_t ctx); -static int lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx); +static int lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, bool* dp_has_iocount, vfs_context_t ctx); static int lookup_authorize_search(vnode_t dp, struct componentname *cnp, int dp_authorized_in_cache, vfs_context_t ctx); static void lookup_consider_update_cache(vnode_t dvp, vnode_t vp, struct componentname *cnp, int nc_generation); static int lookup_handle_found_vnode(struct nameidata *ndp, struct componentname *cnp, int rdonly, @@ -125,7 +125,7 @@ static int lookup_handle_emptyname(struct nameidata *ndp, struct co static int lookup_handle_rsrc_fork(vnode_t dp, struct nameidata *ndp, struct componentname *cnp, int wantparent, vfs_context_t ctx); #endif - +extern lck_rw_t rootvnode_rw_lock; /* * Convert a pathname into a pointer to a locked inode. @@ -169,7 +169,7 @@ namei(struct nameidata *ndp) struct vnode *dp; /* the directory we are searching */ struct vnode *usedvp = ndp->ni_dvp; /* store pointer to vp in case we must loop due to * heavy vnode pressure */ - u_long cnpflags = ndp->ni_cnd.cn_flags; /* store in case we have to restore after loop */ + uint32_t cnpflags = ndp->ni_cnd.cn_flags; /* store in case we have to restore after loop */ int error; struct componentname *cnp = &ndp->ni_cnd; vfs_context_t ctx = cnp->cn_context; @@ -183,6 +183,11 @@ namei(struct nameidata *ndp) int volfs_restarts = 0; #endif size_t bytes_copied = 0; + vnode_t rootdir_with_usecount = NULLVP; + vnode_t startdir_with_usecount = NULLVP; + vnode_t usedvp_dp = NULLVP; + int32_t old_count = 0; + bool dp_has_iocount = false; fdp = p->p_fd; @@ -254,12 +259,7 @@ retry_copy: cnp->cn_pnlen, &bytes_copied); } if (error == ENAMETOOLONG && !(cnp->cn_flags & HASBUF)) { - MALLOC_ZONE(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); - if (cnp->cn_pnbuf == NULL) { - error = ENOMEM; - goto error_out; - } - + cnp->cn_pnbuf = zalloc(ZV_NAMEI); cnp->cn_flags |= HASBUF; cnp->cn_pnlen = MAXPATHLEN; bytes_copied = 0; @@ -269,7 +269,8 @@ retry_copy: if (error) { goto error_out; } - ndp->ni_pathlen = bytes_copied; + assert(bytes_copied <= MAXPATHLEN); + ndp->ni_pathlen = (u_int)bytes_copied; bytes_copied = 0; /* @@ -300,29 +301,30 @@ retry_copy: char * realpath; int realpath_err; /* Attempt to resolve a legacy volfs style pathname. */ - MALLOC_ZONE(realpath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); - if (realpath) { - /* - * We only error out on the ENAMETOOLONG cases where we know that - * vfs_getrealpath translation succeeded but the path could not fit into - * MAXPATHLEN characters. In other failure cases, we may be dealing with a path - * that legitimately looks like /.vol/1234/567 and is not meant to be translated - */ - if ((realpath_err = vfs_getrealpath(&cnp->cn_pnbuf[6], realpath, MAXPATHLEN, ctx))) { - FREE_ZONE(realpath, MAXPATHLEN, M_NAMEI); - if (realpath_err == ENOSPC || realpath_err == ENAMETOOLONG) { - error = ENAMETOOLONG; - goto error_out; - } - } else { - if (cnp->cn_flags & HASBUF) { - FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); - } - cnp->cn_pnbuf = realpath; - cnp->cn_pnlen = MAXPATHLEN; - ndp->ni_pathlen = strlen(realpath) + 1; - cnp->cn_flags |= HASBUF | CN_VOLFSPATH; + realpath = zalloc(ZV_NAMEI); + /* + * We only error out on the ENAMETOOLONG cases where we know that + * vfs_getrealpath translation succeeded but the path could not fit into + * MAXPATHLEN characters. In other failure cases, we may be dealing with a path + * that legitimately looks like /.vol/1234/567 and is not meant to be translated + */ + if ((realpath_err = vfs_getrealpath(&cnp->cn_pnbuf[6], realpath, MAXPATHLEN, ctx))) { + zfree(ZV_NAMEI, realpath); + if (realpath_err == ENOSPC || realpath_err == ENAMETOOLONG) { + error = ENAMETOOLONG; + goto error_out; } + } else { + size_t tmp_len; + if (cnp->cn_flags & HASBUF) { + zfree(ZV_NAMEI, cnp->cn_pnbuf); + } + cnp->cn_pnbuf = realpath; + cnp->cn_pnlen = MAXPATHLEN; + tmp_len = strlen(realpath) + 1; + assert(tmp_len <= UINT_MAX); + ndp->ni_pathlen = (u_int)tmp_len; + cnp->cn_flags |= HASBUF | CN_VOLFSPATH; } } #endif /* CONFIG_VOLFS */ @@ -344,16 +346,37 @@ retry_copy: error = ENOENT; goto error_out; } - ndp->ni_loopcnt = 0; + if (ndp->ni_flag & NAMEI_NOFOLLOW_ANY) { + ndp->ni_loopcnt = MAXSYMLINKS; + } else { + ndp->ni_loopcnt = 0; + } /* * determine the starting point for the translation. */ - if ((ndp->ni_rootdir = fdp->fd_rdir) == NULLVP) { + proc_dirs_lock_shared(p); + lck_rw_lock_shared(&rootvnode_rw_lock); + + if (!(fdp->fd_flags & FD_CHROOT)) { + ndp->ni_rootdir = rootvnode; + } else { + ndp->ni_rootdir = fdp->fd_rdir; + } + + if (!ndp->ni_rootdir) { if (!(fdp->fd_flags & FD_CHROOT)) { - ndp->ni_rootdir = rootvnode; + printf("rootvnode is not set\n"); + } else { + /* This should be a panic */ + printf("fdp->fd_rdir is not set\n"); } + lck_rw_unlock_shared(&rootvnode_rw_lock); + proc_dirs_unlock_shared(p); + error = ENOENT; + goto error_out; } + cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_usedvp = NULLVP; @@ -367,14 +390,59 @@ retry_copy: } else if (cnp->cn_flags & USEDVP) { dp = ndp->ni_dvp; ndp->ni_usedvp = dp; + usedvp_dp = dp; } else { dp = vfs_context_cwd(ctx); } if (dp == NULLVP || (dp->v_lflag & VL_DEAD)) { + dp = NULLVP; + lck_rw_unlock_shared(&rootvnode_rw_lock); + proc_dirs_unlock_shared(p); error = ENOENT; goto error_out; } + + /* + * We need our own usecount on the root vnode and the starting dir across + * the lookup. There's two things that be done here. We can hold the locks + * (which protect the existing usecounts on the directories) across the + * lookup or take our own usecount. Holding the locks across the lookup can + * cause deadlock issues if we re-enter namei on the same thread so the + * correct thing to do is to acquire our own usecount. + * + * Ideally, the usecount should be obtained by vnode_get->vnode_ref->vnode_put. + * However when this vnode is the rootvnode, that sequence will produce a + * lot of vnode mutex locks and unlocks on a single vnode (the rootvnode) + * and will be highly contended and degrade performance. Since we have + * an existing usecount protected by the locks we hold, we'll just use + * an atomic op to increment the usecount on a vnode which already has one + * and can't be released becasue we have the locks which protect against that + * happening. + */ + rootdir_with_usecount = ndp->ni_rootdir; + old_count = os_atomic_inc_orig(&rootdir_with_usecount->v_usecount, relaxed); + if (old_count < 1) { + panic("(1) invalid pre-increment usecount (%d) for rootdir vnode %p", + old_count, rootdir_with_usecount); + } else if (old_count == INT32_MAX) { + panic("(1) usecount overflow for vnode %p", rootdir_with_usecount); + } + + if ((dp != rootdir_with_usecount) && (dp != usedvp_dp)) { + old_count = os_atomic_inc_orig(&dp->v_usecount, relaxed); + if (old_count < 1) { + panic("(2) invalid pre-increment usecount (%d) for vnode %p", old_count, dp); + } else if (old_count == INT32_MAX) { + panic("(2) usecount overflow for vnode %p", dp); + } + startdir_with_usecount = dp; + } + + /* Now that we have our usecount, release the locks */ + lck_rw_unlock_shared(&rootvnode_rw_lock); + proc_dirs_unlock_shared(p); + ndp->ni_dvp = NULLVP; ndp->ni_vp = NULLVP; @@ -393,8 +461,8 @@ retry_copy: goto error_out; } #endif - ndp->ni_startdir = dp; + dp = NULLVP; if ((error = lookup(ndp))) { goto error_out; @@ -404,15 +472,51 @@ retry_copy: * Check for symbolic link */ if ((cnp->cn_flags & ISSYMLINK) == 0) { + if (startdir_with_usecount) { + vnode_rele(startdir_with_usecount); + startdir_with_usecount = NULLVP; + } + if (rootdir_with_usecount) { + lck_rw_lock_shared(&rootvnode_rw_lock); + if (rootdir_with_usecount == rootvnode) { + old_count = os_atomic_dec_orig(&rootdir_with_usecount->v_usecount, relaxed); + if (old_count < 2) { + /* + * There needs to have been at least 1 usecount left on the rootvnode + */ + panic("(3) Unexpected pre-decrement value (%d) of usecount for rootvnode %p", + old_count, rootdir_with_usecount); + } + rootdir_with_usecount = NULLVP; + } + lck_rw_unlock_shared(&rootvnode_rw_lock); + if (rootdir_with_usecount) { + vnode_rele(rootdir_with_usecount); + rootdir_with_usecount = NULLVP; + } + } + return 0; } continue_symlink: /* Gives us a new path to process, and a starting dir */ - error = lookup_handle_symlink(ndp, &dp, ctx); + error = lookup_handle_symlink(ndp, &dp, &dp_has_iocount, ctx); if (error != 0) { break; } + if (dp_has_iocount) { + if ((dp != rootdir_with_usecount) && (dp != startdir_with_usecount) && + (dp != usedvp_dp)) { + if (startdir_with_usecount) { + vnode_rele(startdir_with_usecount); + } + vnode_ref_ext(dp, 0, VNODE_REF_FORCE); + startdir_with_usecount = dp; + } + vnode_put(dp); + dp_has_iocount = false; + } } /* * only come here if we fail to handle a SYMLINK... @@ -428,9 +532,32 @@ out_drop: vnode_put(ndp->ni_vp); } error_out: + if (startdir_with_usecount) { + vnode_rele(startdir_with_usecount); + startdir_with_usecount = NULLVP; + } + if (rootdir_with_usecount) { + lck_rw_lock_shared(&rootvnode_rw_lock); + if (rootdir_with_usecount == rootvnode) { + old_count = os_atomic_dec_orig(&rootdir_with_usecount->v_usecount, relaxed); + if (old_count < 2) { + /* + * There needs to have been at least 1 usecount left on the rootvnode + */ + panic("(4) Unexpected pre-decrement value (%d) of usecount for rootvnode %p", + old_count, rootdir_with_usecount); + } + lck_rw_unlock_shared(&rootvnode_rw_lock); + } else { + lck_rw_unlock_shared(&rootvnode_rw_lock); + vnode_rele(rootdir_with_usecount); + } + rootdir_with_usecount = NULLVP; + } + if ((cnp->cn_flags & HASBUF)) { cnp->cn_flags &= ~HASBUF; - FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); + zfree(ZV_NAMEI, cnp->cn_pnbuf); } cnp->cn_pnbuf = NULL; ndp->ni_vp = NULLVP; @@ -1121,13 +1248,15 @@ dirloop: tdp = dp; dp = tdp->v_mount->mnt_vnodecovered; - vnode_put(tdp); - if ((vnode_getwithref(dp))) { + vnode_put(tdp); dp = NULLVP; error = ENOENT; goto bad; } + + vnode_put(tdp); + ndp->ni_dvp = dp; dp_authorized = 0; } @@ -1323,7 +1452,7 @@ lookup_traverse_union(vnode_t dvp, vnode_t *new_dvp, vfs_context_t ctx) { char *path = NULL, *pp; const char *name, *np; - int len; + size_t len; int error = 0; struct nameidata nd; vnode_t vp = dvp; @@ -1338,7 +1467,7 @@ lookup_traverse_union(vnode_t dvp, vnode_t *new_dvp, vfs_context_t ctx) return 0; } - path = (char *) kalloc(MAXPATHLEN); + path = (char *) zalloc(ZV_NAMEI); if (path == NULL) { error = ENOMEM; goto done; @@ -1360,7 +1489,7 @@ lookup_traverse_union(vnode_t dvp, vnode_t *new_dvp, vfs_context_t ctx) goto done; } len = strlen(name); - if ((len + 1) > (pp - path)) { // Enough space for this name ? + if ((len + 1) > (size_t)(pp - path)) { // Enough space for this name ? error = ENAMETOOLONG; vnode_putname(name); goto done; @@ -1386,7 +1515,7 @@ lookup_traverse_union(vnode_t dvp, vnode_t *new_dvp, vfs_context_t ctx) nameidone(&nd); done: if (path) { - kfree(path, MAXPATHLEN); + zfree(ZV_NAMEI, path); } return error; } @@ -1533,7 +1662,7 @@ out: * at which to start a lookup with a resolved path, and all other iocounts dropped. */ static int -lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) +lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, bool *new_dp_has_iocount, vfs_context_t ctx) { int error; char *cp; /* pointer into pathname argument */ @@ -1552,6 +1681,7 @@ lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) vnode_t dp; char *tmppn; u_int rsrclen = (cnp->cn_flags & CN_WANTSRSRCFORK) ? sizeof(_PATH_RSRCFORKSPEC) : 0; + bool dp_has_iocount = false; if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { return ELOOP; @@ -1568,10 +1698,7 @@ lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) } if (need_newpathbuf) { - MALLOC_ZONE(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); - if (cp == NULL) { - return ENOMEM; - } + cp = zalloc(ZV_NAMEI); } else { cp = cnp->cn_pnbuf; } @@ -1583,7 +1710,7 @@ lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) error = VNOP_READLINK(ndp->ni_vp, auio, ctx); if (error) { if (need_newpathbuf) { - FREE_ZONE(cp, MAXPATHLEN, M_NAMEI); + zfree(ZV_NAMEI, cp); } return error; } @@ -1596,21 +1723,19 @@ lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) linklen = MAXPATHLEN - (u_int)uio_resid(auio); if (linklen + ndp->ni_pathlen + rsrclen > MAXPATHLEN) { if (need_newpathbuf) { - FREE_ZONE(cp, MAXPATHLEN, M_NAMEI); + zfree(ZV_NAMEI, cp); } return ENAMETOOLONG; } if (need_newpathbuf) { - long len = cnp->cn_pnlen; - tmppn = cnp->cn_pnbuf; bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); cnp->cn_pnbuf = cp; cnp->cn_pnlen = MAXPATHLEN; if ((cnp->cn_flags & HASBUF)) { - FREE_ZONE(tmppn, len, M_NAMEI); + zfree(ZV_NAMEI, tmppn); } else { cnp->cn_flags |= HASBUF; } @@ -1628,11 +1753,10 @@ lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) dp = ndp->ni_dvp; /* - * get rid of references returned via 'lookup' + * get rid of reference returned via 'lookup' + * ni_dvp is released only if we restart at /. */ vnode_put(ndp->ni_vp); - vnode_put(ndp->ni_dvp); /* ALWAYS have a dvp for a symlink */ - ndp->ni_vp = NULLVP; ndp->ni_dvp = NULLVP; @@ -1640,6 +1764,7 @@ lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) * Check if symbolic link restarts us at the root */ if (*(cnp->cn_nameptr) == '/') { + vnode_put(dp); /* ALWAYS have a dvp for a symlink */ while (*(cnp->cn_nameptr) == '/') { cnp->cn_nameptr++; ndp->ni_pathlen--; @@ -1647,9 +1772,12 @@ lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) if ((dp = ndp->ni_rootdir) == NULLVP) { return ENOENT; } + } else { + dp_has_iocount = true; } *new_dp = dp; + *new_dp_has_iocount = dp_has_iocount; return 0; } @@ -1780,124 +1908,109 @@ nameidone(struct nameidata *ndp) ndp->ni_cnd.cn_pnbuf = NULL; ndp->ni_cnd.cn_flags &= ~HASBUF; - FREE_ZONE(tmp, ndp->ni_cnd.cn_pnlen, M_NAMEI); + zfree(ZV_NAMEI, tmp); } } /* - * Log (part of) a pathname using the KERNEL_DEBUG_CONSTANT mechanism, as used - * by fs_usage. The path up to and including the current component name are - * logged. Up to NUMPARMS*4 bytes of pathname will be logged. If the path - * to be logged is longer than that, then the last NUMPARMS*4 bytes are logged. - * That is, the truncation removes the leading portion of the path. - * - * The logging is done via multiple KERNEL_DEBUG_CONSTANT calls. The first one - * is marked with DBG_FUNC_START. The last one is marked with DBG_FUNC_END - * (in addition to DBG_FUNC_START if it is also the first). There may be - * intermediate ones with neither DBG_FUNC_START nor DBG_FUNC_END. + * Log (part of) a pathname using kdebug, as used by fs_usage. The path up to + * and including the current component name are logged. Up to NUMPARMS * 4 + * bytes of pathname will be logged. If the path to be logged is longer than + * that, then the last NUMPARMS * 4 bytes are logged. That is, the truncation + * removes the leading portion of the path. * - * The first KERNEL_DEBUG_CONSTANT passes the vnode pointer and 12 bytes of - * pathname. The remaining KERNEL_DEBUG_CONSTANT calls add 16 bytes of pathname - * each. The minimum number of KERNEL_DEBUG_CONSTANT calls required to pass - * the path are used. Any excess padding in the final KERNEL_DEBUG_CONSTANT - * (because not all of the 12 or 16 bytes are needed for the remainder of the - * path) is set to zero bytes, or '>' if there is more path beyond the - * current component name (usually because an intermediate component was not - * found). + * The logging is done via multiple KDBG_RELEASE calls. The first one is marked + * with DBG_FUNC_START. The last one is marked with DBG_FUNC_END (in addition + * to DBG_FUNC_START if it is also the first). There may be intermediate ones + * with neither DBG_FUNC_START nor DBG_FUNC_END. * - * NOTE: If the path length is greater than NUMPARMS*4, or is not of the form - * 12+N*16, there will be no padding. + * The first event passes the vnode pointer and 24 or 32 (on K32, 12 or 24) + * bytes of pathname. The remaining events add 32 (on K32, 16) bytes of + * pathname each. The minimum number of events required to pass the path are + * used. Any excess padding in the final event (because not all of the 24 or 32 + * (on K32, 12 or 16) bytes are needed for the remainder of the path) is set to + * zero bytes, or '>' if there is more path beyond the current component name + * (usually because an intermediate component was not found). * - * TODO: If there is more path beyond the current component name, should we - * force some padding? For example, a lookup for /foo_bar_baz/spam that - * fails because /foo_bar_baz is not found will only log "/foo_bar_baz", with - * no '>' padding. But /foo_bar/spam would log "/foo_bar>>>>". + * NOTE: If the path length is greater than NUMPARMS * 4, or is not of the form + * 24 + N * 32 (or on K32, 12 + N * 16), there will be no padding. */ #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) void -kdebug_vfs_lookup(long *dbg_parms, int dbg_namelen, void *dp, uint32_t flags) +kdebug_vfs_lookup(unsigned long *path_words, int path_len, void *vnp, + uint32_t flags) { - int code; - unsigned int i; - bool lookup = flags & KDBG_VFS_LOOKUP_FLAG_LOOKUP; bool noprocfilt = flags & KDBG_VFS_LOOKUP_FLAG_NOPROCFILT; - /* - * In the event that we collect multiple, consecutive pathname - * entries, we must mark the start of the path's string and the end. - */ - if (lookup) { - code = VFS_LOOKUP | DBG_FUNC_START; - } else { - code = VFS_LOOKUP_DONE | DBG_FUNC_START; - } + assert(path_len >= 0); - if (dbg_namelen <= (int)(3 * sizeof(long))) { + int code = ((flags & KDBG_VFS_LOOKUP_FLAG_LOOKUP) ? VFS_LOOKUP : + VFS_LOOKUP_DONE) | DBG_FUNC_START; + + if (path_len <= (3 * (int)sizeof(long))) { code |= DBG_FUNC_END; } if (noprocfilt) { - KDBG_RELEASE_NOPROCFILT(code, kdebug_vnode(dp), dbg_parms[0], - dbg_parms[1], dbg_parms[2]); + KDBG_RELEASE_NOPROCFILT(code, kdebug_vnode(vnp), path_words[0], + path_words[1], path_words[2]); } else { - KDBG_RELEASE(code, kdebug_vnode(dp), dbg_parms[0], dbg_parms[1], - dbg_parms[2]); + KDBG_RELEASE(code, kdebug_vnode(vnp), path_words[0], path_words[1], + path_words[2]); } code &= ~DBG_FUNC_START; - for (i = 3, dbg_namelen -= (3 * sizeof(long)); dbg_namelen > 0; i += 4, dbg_namelen -= (4 * sizeof(long))) { - if (dbg_namelen <= (int)(4 * sizeof(long))) { + for (int i = 3; i * (int)sizeof(long) < path_len; i += 4) { + if ((i + 4) * (int)sizeof(long) >= path_len) { code |= DBG_FUNC_END; } if (noprocfilt) { - KDBG_RELEASE_NOPROCFILT(code, dbg_parms[i], dbg_parms[i + 1], - dbg_parms[i + 2], dbg_parms[i + 3]); + KDBG_RELEASE_NOPROCFILT(code, path_words[i], path_words[i + 1], + path_words[i + 2], path_words[i + 3]); } else { - KDBG_RELEASE(code, dbg_parms[i], dbg_parms[i + 1], dbg_parms[i + 2], - dbg_parms[i + 3]); + KDBG_RELEASE(code, path_words[i], path_words[i + 1], + path_words[i + 2], path_words[i + 3]); } } } void -kdebug_lookup_gen_events(long *dbg_parms, int dbg_namelen, void *dp, - bool lookup) +kdebug_lookup_gen_events(long *path_words, int path_len, void *vnp, bool lookup) { - kdebug_vfs_lookup(dbg_parms, dbg_namelen, dp, + assert(path_len >= 0); + kdebug_vfs_lookup((unsigned long *)path_words, path_len, vnp, lookup ? KDBG_VFS_LOOKUP_FLAG_LOOKUP : 0); } void -kdebug_lookup(vnode_t dp, struct componentname *cnp) +kdebug_lookup(vnode_t vnp, struct componentname *cnp) { - int dbg_namelen; - char *dbg_nameptr; - long dbg_parms[NUMPARMS]; - - /* Collect the pathname for tracing */ - dbg_namelen = (cnp->cn_nameptr - cnp->cn_pnbuf) + cnp->cn_namelen; - dbg_nameptr = cnp->cn_nameptr + cnp->cn_namelen; + unsigned long path_words[NUMPARMS]; - if (dbg_namelen > (int)sizeof(dbg_parms)) { - dbg_namelen = sizeof(dbg_parms); - } - dbg_nameptr -= dbg_namelen; + /* + * Truncate the leading portion of the path to fit in path_words. + */ + char *path_end = cnp->cn_nameptr + cnp->cn_namelen; + size_t path_len = MIN(path_end - cnp->cn_pnbuf, + (ssize_t)sizeof(path_words)); + assert(path_len >= 0); + char *path_trunc = path_end - path_len; - /* Copy the (possibly truncated) path itself */ - memcpy(dbg_parms, dbg_nameptr, dbg_namelen); + memcpy(path_words, path_trunc, path_len); - /* Pad with '\0' or '>' */ - if (dbg_namelen < (int)sizeof(dbg_parms)) { - memset((char *)dbg_parms + dbg_namelen, - *(cnp->cn_nameptr + cnp->cn_namelen) ? '>' : 0, - sizeof(dbg_parms) - dbg_namelen); + /* + * Pad with '\0' or '>'. + */ + if (path_len < (ssize_t)sizeof(path_words)) { + bool complete_str = *(cnp->cn_nameptr + cnp->cn_namelen) == '\0'; + memset((char *)path_words + path_len, complete_str ? '\0' : '>', + sizeof(path_words) - path_len); } - kdebug_vfs_lookup(dbg_parms, dbg_namelen, (void *)dp, - KDBG_VFS_LOOKUP_FLAG_LOOKUP); + kdebug_vfs_lookup(path_words, (int)path_len, vnp, KDBG_VFS_LOOKUP_FLAG_LOOKUP); } #else /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) */ @@ -1959,7 +2072,7 @@ vfs_getrealpath(const char * path, char * realpath, size_t bufsize, vfs_context_ struct mount *mp = NULL; char *str; char ch; - uint32_t id; + unsigned long id; ino64_t ino; int error; int length; @@ -1974,7 +2087,10 @@ vfs_getrealpath(const char * path, char * realpath, size_t bufsize, vfs_context_ } ch = *str; - mp = mount_lookupby_volfsid(id, 1); + if (id > INT_MAX) { + return ENOENT; + } + mp = mount_lookupby_volfsid((int)id, 1); if (mp == NULL) { return EINVAL; /* unexpected failure */ } @@ -2017,11 +2133,11 @@ vfs_getrealpath(const char * path, char * realpath, size_t bufsize, vfs_context_ realpath[0] = '\0'; /* Get the absolute path to this vnode. */ - error = build_path(vp, realpath, bufsize, &length, 0, ctx); + error = build_path(vp, realpath, (int)bufsize, &length, 0, ctx); vnode_put(vp); if (error == 0 && *str != '\0') { - int attempt = strlcat(realpath, str, MAXPATHLEN); + size_t attempt = strlcat(realpath, str, MAXPATHLEN); if (attempt > MAXPATHLEN) { error = ENAMETOOLONG; }