Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Sep 2025 17:38:11 GMT
From:      Olivier Certner <olce@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: c5a813c9f486 - main - vfs cache: Add vn_fullpath_jail(), factor out common code
Message-ID:  <202509291738.58THcBjU060982@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=c5a813c9f486da49551c3be2e7700ca0cb0a489a

commit c5a813c9f486da49551c3be2e7700ca0cb0a489a
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2025-09-26 10:18:12 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
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
+.\" <olce@FreeBSD.org> 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,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509291738.58THcBjU060982>