From nobody Mon Sep 29 17:38:11 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cb7h35lyfz68Yjr; Mon, 29 Sep 2025 17:38:11 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cb7h35GC9z3Wjp; Mon, 29 Sep 2025 17:38:11 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759167491; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=I81UzgxV5q5X5hiqBzWZW9P1WxgM7IruWWAJHfBX0KU=; b=MmbtCoVG8xrzQbLU+UdLobMNutCPZUZ+LbxqFOT9M7HIHH1pUR/4JnQyf2AnY0pnonpnoP MxjWjVPs0m50OUTak0BD4PpBF6FVCcTMGsoom92d9QlxbWk76PsDbMwYU55+31D4PpjGIV 6md29qmsDr9Q1HZz3krb0b/4UGJa1Ud2z4mWMd8VAKLawRETsyo0vTHzq0o/VuM6xtFjFK gPlFH8iYz5R+Kptm5l+W5kkRgh1MwNFFDCr3zZBHwXi0tsau4sTqsR8HKF0YuQI3m/GsTW Sr5lmxpvtrTOwhRgkGDd2BP1srt2PlX+Dt1rBNfVzRxQ9VT+FS3oS3NYi6vYVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759167491; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=I81UzgxV5q5X5hiqBzWZW9P1WxgM7IruWWAJHfBX0KU=; b=qAPhfpz3/hX2kJcuKoGNrSNz/efVymkPfyLeTJGio8Z9DiC/DWssckmO9jVuCGibGWG9Mn t965lQ7N4zwINhMKxoDrDC0MYrEPfc87ooSr/YHPii88pfHEvkl1VGndd3b3QSGQo7OC1r kW4Ve4Ico5a1eOO3ybHC2CMRUY4k0FcLgW20JBOT94JBo+uvvLwfVnrOK9MVhtmDQYLKpo ddisDK0spB7CKa9cJr4N1kkD2EWcMKnaxERdkSuv4QsPRhy58xadSyAHzOSebnnjFu6aI/ qM6diK2fpSXSX38HBELdnEeohT8qPNh93ANoRCuVeoIfAVBxJweVUnOF8YJKvw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1759167491; a=rsa-sha256; cv=none; b=coiqXBmzICY388+jlrq95StytbH6UWHl/cLig/ST+MkxItlHXILhsqCvfmbt9ALwxj/uDE OKvI3xPY4lwhZFcOjx9JKgadIkS1T+WK3AJeWAkKrl3mYGwCGiL7QxOemwqF70cTyveQ9r URk5lXye4UVuaWBcTKN7WLgRazKjiq+58dOT1oc/TyoslRSEzgOEV7pHzTfU9B5k+4BEOe lLr7a4/Y3FjzyMVyAj0SNhcN4zWc8djCFWczo55PkaxJhGL/8iwkx3XwQPNTmdITlD1tYf YxgU0hrDqWRUhe2ybC5dTyMmhE3vKP0N0bSGQMa3bpkcAARhXAId75Bh9r7ntA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cb7h34rpRz1FBd; Mon, 29 Sep 2025 17:38:11 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 58THcBgw060985; Mon, 29 Sep 2025 17:38:11 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 58THcBjU060982; Mon, 29 Sep 2025 17:38:11 GMT (envelope-from git) Date: Mon, 29 Sep 2025 17:38:11 GMT Message-Id: <202509291738.58THcBjU060982@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Olivier Certner Subject: git: c5a813c9f486 - main - vfs cache: Add vn_fullpath_jail(), factor out common code List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: olce X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: c5a813c9f486da49551c3be2e7700ca0cb0a489a Auto-Submitted: auto-generated The branch main has been updated by olce: URL: https://cgit.FreeBSD.org/src/commit/?id=c5a813c9f486da49551c3be2e7700ca0cb0a489a commit c5a813c9f486da49551c3be2e7700ca0cb0a489a Author: Olivier Certner AuthorDate: 2025-09-26 10:18:12 +0000 Commit: Olivier Certner CommitDate: 2025-09-29 17:37:08 +0000 vfs cache: Add vn_fullpath_jail(), factor out common code Introduce vn_fullpath_jail(), which returns a path to the passed vnode relative to the current jail's root. It will be used by mac_do(4) in a subsequent commit. Factor out common code between the new variant and vn_fullpath(). While here, rework the comments a bit. Add vn_fullpath_jail() to the vn_fullpath.9 manual page. While here, document all the existing public vn_fullpath*() functions. Reviewed by: kib (except latest manual page changes) MFC after: 3 days Event: EuroBSDCon 2025 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D52757 --- share/man/man9/Makefile | 1 + share/man/man9/vn_fullpath.9 | 120 +++++++++++++++++++++++++++++++++++-------- sys/kern/vfs_cache.c | 52 ++++++++++++++++--- sys/sys/vnode.h | 1 + 4 files changed, 144 insertions(+), 30 deletions(-) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index d2282b3e5a80..67f3fdd2f6e5 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -2455,6 +2455,7 @@ MLINKS+=vm_page_insert.9 vm_page_remove.9 MLINKS+=vm_page_wire.9 vm_page_unwire.9 \ vm_page_wire.9 vm_page_unwire_noq.9 \ vm_page_wire.9 vm_page_wire_mapped.9 +MLINKS+=vn_fullpath.9 vn_fullpath_jail.9 MLINKS+=VOP_ACCESS.9 VOP_ACCESSX.9 MLINKS+=VOP_ATTRIB.9 VOP_GETATTR.9 \ VOP_ATTRIB.9 VOP_SETATTR.9 \ diff --git a/share/man/man9/vn_fullpath.9 b/share/man/man9/vn_fullpath.9 index 116f519ec8aa..9815abc3c86c 100644 --- a/share/man/man9/vn_fullpath.9 +++ b/share/man/man9/vn_fullpath.9 @@ -1,6 +1,13 @@ +.\"- +.\" SPDX-License-Identifier: BSD-2-Clause .\" .\" Copyright (c) 2003 Robert N. M. Watson. .\" All rights reserved. +.\" Copyright (c) 2025 The FreeBSD Foundation +.\" +.\" Portions of this documentation were written by Olivier Certner +.\" at Kumacom SARL under sponsorship from the FreeBSD +.\" Foundation. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -25,7 +32,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH .\" DAMAGE. .\" -.Dd June 15, 2021 +.Dd September 29, 2025 .Dt VN_FULLPATH 9 .Os .Sh NAME @@ -35,23 +42,64 @@ .In sys/param.h .In sys/vnode.h .Ft int -.Fo vn_fullpath -.Fa "struct vnode *vp" "char **retbuf" "char **freebuf" +.Fn vn_fullpath "struct vnode *vp" "char **retbuf" "char **freebuf" +.Ft int +.Fn vn_fullpath_jail "struct vnode *vp" "char **retbuf" "char **freebuf" +.Ft int +.Fn vn_fullpath_global "struct vnode *vp" "char **retbuf" "char **freebuf" +.Ft int +.Fo vn_fullpath_hardlink +.Fa "struct vnode *vp" "struct vnode *dvp" +.Fa "const char *hrdl_name" "size_t hrdl_name_length" +.Fa "char **retbuf" "char **freebuf" "size_t *buflen" .Fc .Sh DESCRIPTION The +.Fn vn_fullpath , +.Fn vn_fullpath_jail , +.Fn vn_fullpath_global +and +.Fn vn_fullpath_hardlink +functions make a +.Dq best effort +attempt at generating a string pathname for the passed vnode. +They differ in which directory the returned path is relative to, except for +.Fn vn_fullpath_hardlink +which behaves like .Fn vn_fullpath -function makes a -.Dq "best effort" -attempt to generate a string pathname for -the passed vnode; the resulting path, if any, will be relative to -the root directory of the process associated with the passed thread pointer. +in this respect and is described at the end. +.Pp The .Fn vn_fullpath -function -is implemented by inspecting the VFS name cache, and attempting to -reconstruct a path from the process root to the object. +function returns a path relative to the root directory of the process associated +with the passed thread pointer. +That root directory is either the system's or the thread's process' containing +jail's root directory, or some descendant directory of such established by some +.Xr chroot 2 +call. +The +.Fn vn_fullpath_jail +function returns a path relative to the passed thread's process' current jail's +root, ignoring intervening +.Xr chroot 2 +calls possibly made inside that jail. +The +.Fn vn_fullpath_global +function returns the full path from the system root, ignoring all jail roots and +.Xr chroot 2 +calls. +.Pp +Paths that the kernel intends to communicate to the passed user thread should +exclusively be obtained via +.Fn vn_fullpath . +Paths obtained via +.Fn vn_fullpath_jail +or +.Fn vn_fullpath_global +are only useful for specific kernel checks or auditing purposes. .Pp +All these functions are implemented by inspecting the VFS name cache, and +attempting to reconstruct a path from the process root to the object. This process is necessarily unreliable for several reasons: intermediate entries in the path may not be found in the cache; files may have more than one name (hard links), not all file systems use the name cache @@ -64,7 +112,7 @@ a vnode pointer value, or a device number and inode number. Code consuming the results of this function should anticipate (and properly handle) failure. .Pp -Its arguments are: +These functions take the following arguments: .Bl -tag -width ".Fa freebuf" .It Fa vp The vnode to search for. @@ -72,17 +120,13 @@ No need to be locked by the caller. .It Fa retbuf Pointer to a .Vt "char *" -that -.Fn vn_fullpath -may (on success) point at a newly -allocated buffer containing the resulting pathname. +that may be set (on success) to point at a newly allocated buffer containing the +resulting pathname. .It Fa freebuf Pointer to a .Vt "char *" -that -.Fn vn_fullpath -may (on success) point at a buffer -to be freed, when the caller is done with +that may be set (on success) to point at a buffer to be freed, when the caller +is done with .Fa retbuf . .El .Pp @@ -110,11 +154,43 @@ and if so, invoke .Xr free 9 with a pool type of .Dv M_TEMP . +.Pp +The +.Fn vn_fullpath_hardlink +function is a convenience wrapper which automatically appends the hardlink name +passed via arguments +.Fa hrdl_name +and +.Fa hrdl_name_length +to the result of calling +.Fn vn_fullpath +on the vnode's parent directory. +It requires the results of a prior call to +.Xr namei 9 +with flag +.Dv WANTPARENT +to be passed in the +.Fa vp +and +.Fa dvp +arguments. +Argument +.Fa buflen +must point to a valid storage containing the size of the desired buffer, which +will be reduced to +.Dv MAXPATHLEN +if in excess of it. .Sh RETURN VALUES If the vnode is successfully converted to a pathname, 0 is returned; otherwise, an error number is returned. .Sh SEE ALSO .Xr free 9 .Sh AUTHORS -This manual page was written by -.An Robert Watson Aq Mt rwatson@FreeBSD.org . +.An -nosplit +This manual page was initally written by +.An Robert Watson Aq Mt rwatson@FreeBSD.org +to describe the +.Fn vn_fullpath +function. +The descriptions of the other related functions were added by +.An Olivier Certner Aq Mt olce@FreeBSD.org . diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 13abb9171234..557e451f9a45 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -3340,12 +3340,10 @@ sys___realpathat(struct thread *td, struct __realpathat_args *uap) uap->flags, UIO_USERSPACE)); } -/* - * Retrieve the full filesystem path that correspond to a vnode from the name - * cache (if available) - */ -int -vn_fullpath(struct vnode *vp, char **retbuf, char **freebuf) +static int +vn_fullpath_up_to_pwd_vnode(struct vnode *vp, + struct vnode *(*const get_pwd_vnode)(const struct pwd *), + char **retbuf, char **freebuf) { struct pwd *pwd; char *buf; @@ -3359,11 +3357,13 @@ vn_fullpath(struct vnode *vp, char **retbuf, char **freebuf) buf = malloc(buflen, M_TEMP, M_WAITOK); vfs_smr_enter(); pwd = pwd_get_smr(); - error = vn_fullpath_any_smr(vp, pwd->pwd_rdir, buf, retbuf, &buflen, 0); + error = vn_fullpath_any_smr(vp, get_pwd_vnode(pwd), buf, retbuf, + &buflen, 0); VFS_SMR_ASSERT_NOT_ENTERED(); if (error < 0) { pwd = pwd_hold(curthread); - error = vn_fullpath_any(vp, pwd->pwd_rdir, buf, retbuf, &buflen); + error = vn_fullpath_any(vp, get_pwd_vnode(pwd), buf, retbuf, + &buflen); pwd_drop(pwd); } if (error == 0) @@ -3373,6 +3373,42 @@ vn_fullpath(struct vnode *vp, char **retbuf, char **freebuf) return (error); } +static inline struct vnode * +get_rdir(const struct pwd *pwd) +{ + return (pwd->pwd_rdir); +} + +/* + * Produce a filesystem path that starts from the current chroot directory and + * corresponds to the passed vnode, using the name cache (if available). + */ +int +vn_fullpath(struct vnode *vp, char **retbuf, char **freebuf) +{ + return (vn_fullpath_up_to_pwd_vnode(vp, get_rdir, retbuf, freebuf)); +} + +static inline struct vnode * +get_jdir(const struct pwd *pwd) +{ + return (pwd->pwd_jdir); +} + +/* + * Produce a filesystem path that starts from the current jail's root directory + * and corresponds to the passed vnode, using the name cache (if available). + * + * This function allows to ignore chroots done inside a jail (or the host), + * allowing path checks to remain unaffected by privileged or unprivileged + * chroot calls. + */ +int +vn_fullpath_jail(struct vnode *vp, char **retbuf, char **freebuf) +{ + return (vn_fullpath_up_to_pwd_vnode(vp, get_jdir, retbuf, freebuf)); +} + /* * This function is similar to vn_fullpath, but it attempts to lookup the * pathname relative to the global root mount point. This is required for the diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 6d50583dc1b3..0bf438a1b821 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -714,6 +714,7 @@ int speedup_syncer(void); int vn_vptocnp(struct vnode **vp, char *buf, size_t *buflen); int vn_getcwd(char *buf, char **retbuf, size_t *buflen); int vn_fullpath(struct vnode *vp, char **retbuf, char **freebuf); +int vn_fullpath_jail(struct vnode *vp, char **retbuf, char **freebuf); int vn_fullpath_global(struct vnode *vp, char **retbuf, char **freebuf); int vn_fullpath_hardlink(struct vnode *vp, struct vnode *dvp, const char *hdrl_name, size_t hrdl_name_length, char **retbuf,