git: a1d74b2dab78 - main - Allow realpath to work for file mounts
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 19 Dec 2022 16:50:34 UTC
The branch main has been updated by dfr: URL: https://cgit.FreeBSD.org/src/commit/?id=a1d74b2dab78d56582126b4944b435d00747f601 commit a1d74b2dab78d56582126b4944b435d00747f601 Author: Doug Rabson <dfr@FreeBSD.org> AuthorDate: 2022-12-04 15:53:07 +0000 Commit: Doug Rabson <dfr@FreeBSD.org> CommitDate: 2022-12-19 16:46:27 +0000 Allow realpath to work for file mounts For file mounts, the directory vnode is not available from namei and this prevents the use of vn_fullpath_hardlink. In this case, we can use the vnode which was covered by the file mount with vn_fullpath. This also disallows file mounts over files with link counts greater than one to ensure a deterministic path to the mount point. Reviewed by: mjg, kib Tested by: pho --- sys/kern/vfs_cache.c | 28 ++++++++++++++++++++++++++-- sys/kern/vfs_mount.c | 5 +++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index f2dd8328278d..47065cf85bb5 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -3147,12 +3147,36 @@ kern___realpathat(struct thread *td, int fd, const char *path, char *buf, pathseg, path, fd, &cap_fstat_rights); if ((error = namei(&nd)) != 0) return (error); - error = vn_fullpath_hardlink(nd.ni_vp, nd.ni_dvp, nd.ni_cnd.cn_nameptr, - nd.ni_cnd.cn_namelen, &retbuf, &freebuf, &size); + + if (nd.ni_vp->v_type == VREG && nd.ni_dvp->v_type != VDIR && + (nd.ni_vp->v_vflag & VV_ROOT) != 0) { + /* + * This happens if vp is a file mount. The call to + * vn_fullpath_hardlink can panic if path resolution can't be + * handled without the directory. + * + * To resolve this, we find the vnode which was mounted on - + * this should have a unique global path since we disallow + * mounting on linked files. + */ + struct vnode *covered_vp; + error = vn_lock(nd.ni_vp, LK_SHARED); + if (error != 0) + goto out; + covered_vp = nd.ni_vp->v_mount->mnt_vnodecovered; + vref(covered_vp); + VOP_UNLOCK(nd.ni_vp); + error = vn_fullpath(covered_vp, &retbuf, &freebuf); + vrele(covered_vp); + } else { + error = vn_fullpath_hardlink(nd.ni_vp, nd.ni_dvp, nd.ni_cnd.cn_nameptr, + nd.ni_cnd.cn_namelen, &retbuf, &freebuf, &size); + } if (error == 0) { error = copyout(retbuf, buf, size); free(freebuf, M_TEMP); } +out: vrele(nd.ni_vp); vrele(nd.ni_dvp); NDFREE_PNBUF(&nd); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 8001604d2855..8de9d3c4fff8 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1108,6 +1108,11 @@ vfs_domount_first( if (vfsp->vfc_flags & VFCF_FILEMOUNT) { if (error == 0 && vp->v_type != VDIR && vp->v_type != VREG) error = EINVAL; + /* + * For file mounts, ensure that there is only one hardlink to the file. + */ + if (error == 0 && vp->v_type == VREG && va.va_nlink != 1) + error = EINVAL; } else { if (error == 0 && vp->v_type != VDIR) error = ENOTDIR;