Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Feb 2026 16:26:37 +0000
From:      Gordon Tetlow <gordon@FreeBSD.org>
To:        doc-committers@FreeBSD.org, dev-commits-doc-all@FreeBSD.org
Subject:   git: 2cbb6f0c05 - main - Add SA-26:04 and SA-26:05.
Message-ID:  <699dd13d.3143f.108afe9e@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by gordon:

URL: https://cgit.FreeBSD.org/doc/commit/?id=2cbb6f0c05d1872fca1d0ec949ff7b844ca1cc0d

commit 2cbb6f0c05d1872fca1d0ec949ff7b844ca1cc0d
Author:     Gordon Tetlow <gordon@FreeBSD.org>
AuthorDate: 2026-02-24 16:26:10 +0000
Commit:     Gordon Tetlow <gordon@FreeBSD.org>
CommitDate: 2026-02-24 16:26:10 +0000

    Add SA-26:04 and SA-26:05.
    
    Approved by:    so
---
 website/data/security/advisories.toml              |    8 +
 .../security/advisories/FreeBSD-SA-26:04.jail.asc  |  165 +++
 .../security/advisories/FreeBSD-SA-26:05.route.asc |  161 +++
 .../static/security/patches/SA-26:04/jail-13.patch | 1132 +++++++++++++++++++
 .../security/patches/SA-26:04/jail-13.patch.asc    |   16 +
 .../static/security/patches/SA-26:04/jail-14.patch | 1173 ++++++++++++++++++++
 .../security/patches/SA-26:04/jail-14.patch.asc    |   16 +
 .../static/security/patches/SA-26:05/route.patch   |   13 +
 .../security/patches/SA-26:05/route.patch.asc      |   16 +
 9 files changed, 2700 insertions(+)

diff --git a/website/data/security/advisories.toml b/website/data/security/advisories.toml
index c1c95b201a..18fcab9bf1 100644
--- a/website/data/security/advisories.toml
+++ b/website/data/security/advisories.toml
@@ -1,6 +1,14 @@
 # Sort advisories by year, month and day
 # $FreeBSD$
 
+[[advisories]]
+name = "FreeBSD-SA-26:05.route"
+date = "2026-02-24"
+
+[[advisories]]
+name = "FreeBSD-SA-26:04.jail"
+date = "2026-02-24"
+
 [[advisories]]
 name = "FreeBSD-SA-26:03.blocklistd"
 date = "2026-02-10"
diff --git a/website/static/security/advisories/FreeBSD-SA-26:04.jail.asc b/website/static/security/advisories/FreeBSD-SA-26:04.jail.asc
new file mode 100644
index 0000000000..92716c237c
--- /dev/null
+++ b/website/static/security/advisories/FreeBSD-SA-26:04.jail.asc
@@ -0,0 +1,165 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA512
+
+=============================================================================
+FreeBSD-SA-26:04.jail                                       Security Advisory
+                                                          The FreeBSD Project
+
+Topic:          Jail chroot escape via fd exchange with a different jail
+
+Category:       core
+Module:         jail
+Announced:      2026-02-24
+Affects:        FreeBSD 14.3 and 13.5.
+Corrected:      2025-07-29 12:49:03 UTC (stable/14, 14.3-STABLE)
+                2026-02-24 16:01:32 UTC (releng/14.3, 14.3-RELEASE-p9)
+                2026-02-09 20:44:00 UTC (stable/13, 13.4-STABLE)
+                2026-02-24 16:04:42 UTC (releng/13.5, 13.5-RELEASE-p10)
+CVE Name:       CVE-2025-15576
+
+For general information regarding FreeBSD Security Advisories,
+including descriptions of the fields above, security branches, and the
+following sections, please visit <URL:https://security.FreeBSD.org/>.
+
+I.   Background
+
+Jails are an operating system virtualization technology which allow
+administrators to confine processes within an environment with limited ability
+to affect the system outside of that environment.  In particular, jailed
+processes typically have their filesystem access restricted by a chroot-like
+mechanism.
+
+nullfs(4) is a pseudo-filesystem which allows a directory to be mounted at
+another point in the filesystem hierarchy.
+
+unix domain sockets are a mechanism for interprocess communication.  They
+behave similarly to Internet sockets but are identified by names in the local
+filesystem.  unix domain sockets allow processes to exchange file descriptors
+using control messages.
+
+II.  Problem Description
+
+If two sibling jails are restricted to separate filesystem trees, which is to
+say that neither of the two jail root directories is an ancestor of the other,
+jailed processes may nonetheless be able to access a shared directory via a
+nullfs mount, if the administrator has configured one.
+
+In this case, cooperating processes in the two jails may establish a connection
+using a unix domain socket and exchange directory descriptors with each other.
+
+When performing a filesystem name lookup, at each step of the lookup, the
+kernel checks whether the lookup would descend below the jail root of the
+current process.  If the jail root directory is not encountered, the lookup
+continues.
+
+III. Impact
+
+In a configuration where processes in two different jails are able to exchange
+file descriptors using a unix domain socket, it is possible for a jailed
+process to receive a directory for a descriptor that is below that process'
+jail root.  This enables full filesystem access for a jailed process, breaking
+the chroot.
+
+Note that the system administrator is still responsible for ensuring that an
+unprivileged user on the jail host is not able to pass directory descriptors
+to a jailed process, even in a patched kernel.
+
+IV.  Workaround
+
+No workaround is available.  Note that in order to exploit this problem, an
+attacker requires control over processes in two jails which share a nullfs
+mount in which a unix socket can be installed.
+
+V.   Solution
+
+Upgrade your vulnerable system to a supported FreeBSD stable or
+release / security branch (releng) dated after the correction date.
+
+Perform one of the following:
+
+1) To update your vulnerable system installed from binary distribution sets:
+
+Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms,
+or the i386 platform on FreeBSD 13, which were not installed using base
+system packages, can be updated via the freebsd-update(8) utility:
+
+# freebsd-update fetch
+# freebsd-update install
+# shutdown -r +10min "Rebooting for a security update"
+
+2) To update your vulnerable system via a source code patch:
+
+The following patches have been verified to apply to the applicable
+FreeBSD release branches.
+
+a) Download the relevant patch from the location below, and verify the
+detached PGP signature using your PGP utility.
+
+[FreeBSD 14.3]
+# fetch https://security.FreeBSD.org/patches/SA-26:04/jail-14.patch
+# fetch https://security.FreeBSD.org/patches/SA-26:04/jail-14.patch.asc
+# gpg --verify jail-14.patch.asc
+
+[FreeBSD 13.5]
+# fetch https://security.FreeBSD.org/patches/SA-26:04/jail-13.patch
+# fetch https://security.FreeBSD.org/patches/SA-26:04/jail-13.patch.asc
+# gpg --verify jail-13.patch.asc
+
+b) Apply the patch.  Execute the following commands as root:
+
+# cd /usr/src
+# patch < /path/to/patch
+
+c) Recompile your kernel as described in
+<URL:https://www.FreeBSD.org/handbook/kernelconfig.html>; and reboot the
+system.
+
+VI.  Correction details
+
+This issue is corrected as of the corresponding Git commit hash in the
+following stable and release branches:
+
+Branch/path                             Hash                     Revision
+- -------------------------------------------------------------------------
+stable/14/                              3ad3ab5f9b6e    stable/14-n272076
+releng/14.3/                            fbc35b3e6615  releng/14.3-n271471
+stable/13/                              73530e4c2ea9    stable/13-n259752
+releng/13.5/                            e6b96891ef7c  releng/13.5-n259202
+- -------------------------------------------------------------------------
+
+Run the following command to see which files were modified by a
+particular commit:
+
+# git show --stat <commit hash>
+
+Or visit the following URL, replacing NNNNNN with the hash:
+
+<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>;
+
+To determine the commit count in a working tree (for comparison against
+nNNNNNN in the table above), run:
+
+# git rev-list --count --first-parent HEAD
+
+VII. References
+
+<URL:https://www.cve.org/CVERecord?id=CVE-2025-15576>;
+
+The latest revision of this advisory is available at
+<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:04.jail.asc>;
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAEBCgAdFiEEthUnfoEIffdcgYM7bljekB8AGu8FAmmd0NwACgkQbljekB8A
+Gu9WrxAAzgjxobnwhy+3RrD4XSOViKv7Dk6va/cqZtiP+SEv1lwM86P4aeUbqCOL
+XPGItri1El9gQoBYsLS/b5ODbevV/CBaTeZbGwm129B9xdrJ4lQgQrDBh3qgo55k
+OxQTnZbJgnF0YtjcSnkC+oWs4selpADEevEe2ohVUrV4OjXjVoCc3hVibPPwFh+8
+G5lPqcI26kXXimjb+zC+5yFQwNy/an9sYeiVnYceCuAOxxoV0Uf23Z5Ndc5oPBUD
+lYMfrfuqmuhX6AtxTSU7x4BDx4MGTDIMYjU/LXptzMI5bpvqUy4F4lqx0t8vXV8F
+T8vpbzGt8uhyRoD9Wp9LCIS7PpjBNm3YINY4Zd9z46tiC5ItTSV5mkJzatDB2zW+
+4iMcFQxHFGksHyrGn3epYKm1C3NtbKc5lEVHnKZqg11H2xUtDkTRn8AVcy8a9Bh+
+FDo1+yAb96W5by9UGA7nCdF8xwr9+ea/k6JDDfHxgVsOKzOgXsh7wmJ686kTIT2I
+2REIMLY79xs50Lii5EMvN1oSjXxb7+WFphe+XCoH39JDTI3ekg7EpnFHcXLzMaVt
+rciDlmPBU8h5A8U8GyI359DbIlha2IY5R2yC/opHUkOq/wBDJUZcL2y41BEH11jb
+uFxRavagcRePVrSHSuXOH1vSdmsdrtl/h7HBP83J4X6ZG3nnr90=
+=cwB8
+-----END PGP SIGNATURE-----
diff --git a/website/static/security/advisories/FreeBSD-SA-26:05.route.asc b/website/static/security/advisories/FreeBSD-SA-26:05.route.asc
new file mode 100644
index 0000000000..9e4edbab24
--- /dev/null
+++ b/website/static/security/advisories/FreeBSD-SA-26:05.route.asc
@@ -0,0 +1,161 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA512
+
+=============================================================================
+FreeBSD-SA-26:05.route                                      Security Advisory
+                                                          The FreeBSD Project
+
+Topic:          Local DoS and possible privilege escalation via routing sockets
+
+Category:       core
+Module:         route
+Announced:      2026-02-24
+Credits:        Adam Crosser of the Praetorian Labs team
+Affects:        All supported versions of FreeBSD.
+Corrected:      2026-02-24 16:00:26 UTC (stable/15, 15.0-STABLE)
+                2026-02-24 16:00:39 UTC (releng/15.0, 15.0-RELEASE-p4)
+                2026-02-24 16:00:56 UTC (stable/14, 14.4-STABLE)
+                2026-02-24 16:02:31 UTC (releng/14.4, 14.4-RC1)
+                2026-02-24 16:01:35 UTC (releng/14.3, 14.3-RELEASE-p9)
+                2026-02-24 16:03:17 UTC (stable/13, 13.5-STABLE)
+                2026-02-24 16:04:45 UTC (releng/13.5, 13.5-RELEASE-p10)
+CVE Name:       CVE-2026-3038
+
+For general information regarding FreeBSD Security Advisories,
+including descriptions of the fields above, security branches, and the
+following sections, please visit <URL:https://security.FreeBSD.org/>.
+
+I.   Background
+
+The routing socket interface, route(4), lets users query the state of the
+kernel's routing tables.  Most routing socket operations require root
+privileges, but unprivileged users may send RTM_GET messages to obtain
+information about routing table entries.
+
+II.  Problem Description
+
+The rtsock_msg_buffer() function serializes routing information into a buffer.
+As a part of this, it copies sockaddr structures into a sockaddr_storage
+structure on the stack.  It assumes that the source sockaddr length field had
+already been validated, but this is not necessarily the case, and it's possible
+for a malicious userspace program to craft a request which triggers a 127-byte
+overflow.
+
+In practice, this overflow immediately overwrites the canary for the
+rtsock_msg_buffer() stack frame, resulting in a panic once the function
+returns.
+
+III. Impact
+
+The bug allows an unprivileged user to crash the kernel by triggering a stack
+buffer overflow in rtsock_msg_buffer().  In particular, the overflow will
+corrupt a stack canary value that is verified when the function returns; this
+mitigates the impact of the stack overflow by triggering a kernel panic.
+
+Other kernel bugs may exist which allow userspace to find the canary value and
+thus defeat the mitigation, at which point local privilege escalation may be
+possible.
+
+IV.  Workaround
+
+No workaround is available.
+
+V.   Solution
+
+Upgrade your vulnerable system to a supported FreeBSD stable or
+release / security branch (releng) dated after the correction date.
+
+Perform one of the following:
+
+1) To update your vulnerable system installed from base system packages:
+
+Systems running a 15.0-RELEASE version of FreeBSD on the amd64 or arm64
+platforms, which were installed using base system packages, can be updated
+via the pkg(8) utility:
+
+# pkg upgrade -r FreeBSD-base
+# shutdown -r +10min "Rebooting for a security update"
+
+2) To update your vulnerable system installed from binary distribution sets:
+
+Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms,
+or the i386 platform on FreeBSD 13, which were not installed using base
+system packages, can be updated via the freebsd-update(8) utility:
+
+# freebsd-update fetch
+# freebsd-update install
+# shutdown -r +10min "Rebooting for a security update"
+
+3) To update your vulnerable system via a source code patch:
+
+The following patches have been verified to apply to the applicable
+FreeBSD release branches.
+
+a) Download the relevant patch from the location below, and verify the
+detached PGP signature using your PGP utility.
+
+# fetch https://security.FreeBSD.org/patches/SA-26:05/route.patch
+# fetch https://security.FreeBSD.org/patches/SA-26:05/route.patch.asc
+# gpg --verify route.patch.asc
+
+b) Apply the patch.  Execute the following commands as root:
+
+# cd /usr/src
+# patch < /path/to/patch
+
+c) Recompile your kernel as described in
+<URL:https://www.FreeBSD.org/handbook/kernelconfig.html>; and reboot the
+system.
+
+VI.  Correction details
+
+This issue is corrected as of the corresponding Git commit hash in the
+following stable and release branches:
+
+Branch/path                             Hash                     Revision
+- -------------------------------------------------------------------------
+stable/15/                              df932377e7dd    stable/15-n282455
+releng/15.0/                            5de6a55c70ba  releng/15.0-n281009
+stable/14/                              1eb2beb3686c    stable/14-n273785
+releng/14.4/                            7465d0b094b7  releng/14.4-n273667
+releng/14.3/                            d521badafdaa  releng/14.3-n271474
+stable/13/                              8b476ffc4ea3    stable/13-n259798
+releng/13.5/                            c2e2bfbd9e09  releng/13.5-n259205
+- -------------------------------------------------------------------------
+
+Run the following command to see which files were modified by a
+particular commit:
+
+# git show --stat <commit hash>
+
+Or visit the following URL, replacing NNNNNN with the hash:
+
+<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>;
+
+To determine the commit count in a working tree (for comparison against
+nNNNNNN in the table above), run:
+
+# git rev-list --count --first-parent HEAD
+
+VII. References
+
+<URL:https://www.cve.org/CVERecord?id=CVE-2026-3038>;
+
+The latest revision of this advisory is available at
+<URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-26:05.route.asc>;
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAEBCgAdFiEEthUnfoEIffdcgYM7bljekB8AGu8FAmmdz7cACgkQbljekB8A
+Gu+9ehAAziBGPEv4RtXdh5OPqRkmJrZbxYNsiDmsqCO1alaEq/P64uLSI3ShOEf7
+K51oW4P+pukw13mJ7koDfWIFcJ5Jr4p+4vPIUenHafgXzOB9i6prn9kF0RFJN9zX
+ziUaz8DGKd7B01eUoFj0p5l6rm00Z8q9l47ePOXfa+CS90lZxV/9z55UbmmCioQv
+Ar98kPvaRmrmUqifuj72Jh1Wf69XLMDv4CI7BRumXIQnrHJ1xco4T9hHrHzPyNCf
+cObfVsYMew/OGL2WgqfWvOEbmmC4mSW080kjPNmJxA+WG5fc0xQWaF41Kq1YDSWD
+23SLqgjzTEP7zcsN/bW1k/7maf7lkKUWjtC/sjcqJRPfgWfHjDCVcMTKSjje65ld
+Ml4sw4Ea2+jbOZqNcQhtFLo69atTu3oOgN2Gc677rvpkLl+HSivrX7D/1ULYfE0x
+TbtW8Y8fqyNaPPOc1PktUcvQsZ1Sq8OKghOd/JAv1sKLZnxs61fWEMJKTJZEMHQB
+NOnvw8PO2JPNMgJhPJz1CuD0pUCyTDqHYvfEI6TQikJmqKfrhAOBl8ccfNMyMmje
+ZPW1f6hXud7c11OQXJ/u3QyBe7E+3v9MOf7Tn/mbFviwMx/xmG2VbgAuBBOVx6qb
+QnHv9Ce+szmMV+9i0dj5KlsxhuFfUaDIIc9+iZ/1k8GkjkizDjE=
+=V8QD
+-----END PGP SIGNATURE-----
diff --git a/website/static/security/patches/SA-26:04/jail-13.patch b/website/static/security/patches/SA-26:04/jail-13.patch
new file mode 100644
index 0000000000..d59176e649
--- /dev/null
+++ b/website/static/security/patches/SA-26:04/jail-13.patch
@@ -0,0 +1,1132 @@
+--- sys/compat/cloudabi/cloudabi_fd.c.orig
++++ sys/compat/cloudabi/cloudabi_fd.c
+@@ -389,7 +389,7 @@
+ 	int error, oflags;
+ 
+ 	/* Obtain file descriptor properties. */
+-	error = fget_cap(td, uap->fd, cap_rights_init(&rights), &fp,
++	error = fget_cap(td, uap->fd, cap_rights_init(&rights), NULL, &fp,
+ 	    &fcaps);
+ 	if (error != 0)
+ 		return (error);
+--- sys/fs/fdescfs/fdesc_vnops.c.orig
++++ sys/fs/fdescfs/fdesc_vnops.c
+@@ -515,7 +515,7 @@
+ 		    cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp);
+ 	} else {
+ 		error = getvnode_path(td, fd,
+-		    cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp);
++		    cap_rights_init_one(&rights, CAP_EXTATTR_SET), NULL, &fp);
+ 	}
+ 	if (error) {
+ 		/*
+@@ -652,7 +652,7 @@
+ 	VOP_UNLOCK(vn);
+ 
+ 	td = curthread;
+-	error = fget_cap(td, fd_fd, &cap_no_rights, &fp, NULL);
++	error = fget_cap(td, fd_fd, &cap_no_rights, NULL, &fp, NULL);
+ 	if (error != 0)
+ 		goto out;
+ 
+--- sys/kern/kern_descrip.c.orig
++++ sys/kern/kern_descrip.c
+@@ -114,7 +114,8 @@
+ static void	fdunused(struct filedesc *fdp, int fd);
+ static void	fdused(struct filedesc *fdp, int fd);
+ static int	fget_unlocked_seq(struct filedesc *fdp, int fd,
+-		    cap_rights_t *needrightsp, struct file **fpp, seqc_t *seqp);
++		    const cap_rights_t *needrightsp, uint8_t *flagsp,
++		    struct file **fpp, seqc_t *seqp);
+ static int	getmaxfd(struct thread *td);
+ static u_long	*filecaps_copy_prep(const struct filecaps *src);
+ static void	filecaps_copy_finish(const struct filecaps *src,
+@@ -470,6 +471,8 @@
+ 	return (error);
+ }
+ 
++#define	FD_RESOLVE_BENEATH	2
++
+ int
+ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
+ {
+@@ -519,7 +522,9 @@
+ 		fde = fdeget_locked(fdp, fd);
+ 		if (fde != NULL) {
+ 			td->td_retval[0] =
+-			    (fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0;
++			    ((fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0) |
++			    ((fde->fde_flags & UF_RESOLVE_BENEATH) ?
++			    FD_RESOLVE_BENEATH : 0);
+ 			error = 0;
+ 		}
+ 		FILEDESC_SUNLOCK(fdp);
+@@ -530,8 +535,13 @@
+ 		FILEDESC_XLOCK(fdp);
+ 		fde = fdeget_locked(fdp, fd);
+ 		if (fde != NULL) {
++			/*
++			 * UF_RESOLVE_BENEATH is sticky and cannot be cleared.
++			 */
+ 			fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) |
+-			    (arg & FD_CLOEXEC ? UF_EXCLOSE : 0);
++			    ((arg & FD_CLOEXEC) != 0 ? UF_EXCLOSE : 0) |
++			    ((arg & FD_RESOLVE_BENEATH) != 0 ?
++			    UF_RESOLVE_BENEATH : 0);
+ 			error = 0;
+ 		}
+ 		FILEDESC_XUNLOCK(fdp);
+@@ -2158,7 +2168,8 @@
+ 	seqc_write_begin(&fde->fde_seqc);
+ #endif
+ 	fde->fde_file = fp;
+-	fde->fde_flags = (flags & O_CLOEXEC) != 0 ? UF_EXCLOSE : 0;
++	fde->fde_flags = ((flags & O_CLOEXEC) != 0 ? UF_EXCLOSE : 0) |
++	    ((flags & O_RESOLVE_BENEATH) != 0 ? UF_RESOLVE_BENEATH : 0);
+ 	if (fcaps != NULL)
+ 		filecaps_move(fcaps, &fde->fde_caps);
+ 	else
+@@ -2978,7 +2989,7 @@
+ }
+ 
+ int
+-fget_cap_locked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
++fget_cap_locked(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
+     struct file **fpp, struct filecaps *havecapsp)
+ {
+ 	struct filedescent *fde;
+@@ -3010,8 +3021,8 @@
+ }
+ 
+ int
+-fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp,
+-    struct file **fpp, struct filecaps *havecapsp)
++fget_cap(struct thread *td, int fd, const cap_rights_t *needrightsp,
++    uint8_t *flagsp, struct file **fpp, struct filecaps *havecapsp)
+ {
+ 	struct filedesc *fdp = td->td_proc->p_fd;
+ 	int error;
+@@ -3025,7 +3036,8 @@
+ 
+ 	*fpp = NULL;
+ 	for (;;) {
+-		error = fget_unlocked_seq(fdp, fd, needrightsp, &fp, &seq);
++		error = fget_unlocked_seq(fdp, fd, needrightsp, flagsp, &fp,
++		    &seq);
+ 		if (error != 0)
+ 			return (error);
+ 
+@@ -3089,7 +3101,7 @@
+ 
+ #ifdef CAPABILITIES
+ int
+-fgetvp_lookup_smr(int fd, struct nameidata *ndp, struct vnode **vpp, bool *fsearch)
++fgetvp_lookup_smr(int fd, struct nameidata *ndp, struct vnode **vpp, int *flagsp)
+ {
+ 	const struct filedescent *fde;
+ 	const struct fdescenttbl *fdt;
+@@ -3099,6 +3111,7 @@
+ 	const cap_rights_t *haverights;
+ 	cap_rights_t rights;
+ 	seqc_t seq;
++	int flags;
+ 
+ 	VFS_SMR_ASSERT_ENTERED();
+ 
+@@ -3117,7 +3130,9 @@
+ 		return (EAGAIN);
+ 	if (__predict_false(cap_check_inline_transient(haverights, &rights)))
+ 		return (EAGAIN);
+-	*fsearch = ((fp->f_flag & FSEARCH) != 0);
++	flags = fp->f_flag & FSEARCH;
++	flags |= (fde->fde_flags & UF_RESOLVE_BENEATH) != 0 ?
++	    O_RESOLVE_BENEATH : 0;
+ 	vp = fp->f_vnode;
+ 	if (__predict_false(vp == NULL)) {
+ 		return (EAGAIN);
+@@ -3151,16 +3166,19 @@
+ #endif
+ 	}
+ 	*vpp = vp;
++	*flagsp = flags;
+ 	return (0);
+ }
+ #else
+ int
+-fgetvp_lookup_smr(int fd, struct nameidata *ndp, struct vnode **vpp, bool *fsearch)
++fgetvp_lookup_smr(int fd, struct nameidata *ndp, struct vnode **vpp, int *flagsp)
+ {
++	const struct filedescent *fde;
+ 	const struct fdescenttbl *fdt;
+ 	struct filedesc *fdp;
+ 	struct file *fp;
+ 	struct vnode *vp;
++	int flags;
+ 
+ 	VFS_SMR_ASSERT_ENTERED();
+ 
+@@ -3168,10 +3186,13 @@
+ 	fdt = fdp->fd_files;
+ 	if (__predict_false((u_int)fd >= fdt->fdt_nfiles))
+ 		return (EBADF);
+-	fp = fdt->fdt_ofiles[fd].fde_file;
++	fde = &fdt->fdt_ofiles[fd];
++	fp = fde->fde_file;
+ 	if (__predict_false(fp == NULL))
+ 		return (EAGAIN);
+-	*fsearch = ((fp->f_flag & FSEARCH) != 0);
++	flags = fp->f_flag & FSEARCH;
++	flags |= (fde->fde_flags & UF_RESOLVE_BENEATH) != 0 ?
++	    O_RESOLVE_BENEATH : 0;
+ 	vp = fp->f_vnode;
+ 	if (__predict_false(vp == NULL || vp->v_type != VDIR)) {
+ 		return (EAGAIN);
+@@ -3186,6 +3207,7 @@
+ 		return (EAGAIN);
+ 	filecaps_fill(&ndp->ni_filecaps);
+ 	*vpp = vp;
++	*flagsp = flags;
+ 	return (0);
+ }
+ #endif
+@@ -3199,13 +3221,15 @@
+ 	struct componentname *cnp;
+ 	cap_rights_t rights;
+ 	int error;
++	uint8_t flags;
+ 
+ 	td = curthread;
+ 	rights = *ndp->ni_rightsneeded;
+ 	cap_rights_set_one(&rights, CAP_LOOKUP);
+ 	cnp = &ndp->ni_cnd;
+ 
+-	error = fget_cap(td, ndp->ni_dirfd, &rights, &fp, &ndp->ni_filecaps);
++	error = fget_cap(td, ndp->ni_dirfd, &rights, &flags, &fp,
++	    &ndp->ni_filecaps);
+ 	if (__predict_false(error != 0))
+ 		return (error);
+ 	if (__predict_false(fp->f_ops == &badfileops)) {
+@@ -3223,6 +3247,10 @@
+ 	 */
+ 	if ((fp->f_flag & FSEARCH) != 0)
+ 		cnp->cn_flags |= NOEXECCHECK;
++	if ((flags & UF_RESOLVE_BENEATH) != 0) {
++		cnp->cn_flags |= RBENEATH;
++		ndp->ni_resflags |= NIRES_BENEATH;
++	}
+ 	fdrop(fp, td);
+ 
+ #ifdef CAPABILITIES
+@@ -3256,12 +3284,10 @@
+ }
+ 
+ static int
+-fget_unlocked_seq(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
+-    struct file **fpp, seqc_t *seqp)
++fget_unlocked_seq(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
++    uint8_t *flagsp, struct file **fpp, seqc_t *seqp)
+ {
+-#ifdef CAPABILITIES
+ 	const struct filedescent *fde;
+-#endif
+ 	const struct fdescenttbl *fdt;
+ 	struct file *fp;
+ #ifdef CAPABILITIES
+@@ -3269,6 +3295,7 @@
+ 	cap_rights_t haverights;
+ 	int error;
+ #endif
++	uint8_t flags;
+ 
+ 	fdt = fdp->fd_files;
+ 	if (__predict_false((u_int)fd >= fdt->fdt_nfiles))
+@@ -3287,10 +3314,13 @@
+ 		fde = &fdt->fdt_ofiles[fd];
+ 		haverights = *cap_rights_fde_inline(fde);
+ 		fp = fde->fde_file;
++		flags = fde->fde_flags;
+ 		if (!seqc_consistent(fd_seqc(fdt, fd), seq))
+ 			continue;
+ #else
+-		fp = fdt->fdt_ofiles[fd].fde_file;
++		fde = &fdt->fdt_ofiles[fd];
++		flags = fde->fde_flags;
++		fp = fde->fde_file;
+ #endif
+ 		if (fp == NULL)
+ 			return (EBADF);
+@@ -3323,6 +3353,8 @@
+ 		fdrop(fp, curthread);
+ 	}
+ 	*fpp = fp;
++	if (flagsp != NULL)
++		*flagsp = flags;
+ 	if (seqp != NULL) {
+ #ifdef CAPABILITIES
+ 		*seqp = seq;
+@@ -3339,8 +3371,8 @@
+  * racing with itself.
+  */
+ int
+-fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
+-    struct file **fpp)
++fget_unlocked_flags(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
++    uint8_t *flagsp, struct file **fpp)
+ {
+ #ifdef CAPABILITIES
+ 	const struct filedescent *fde;
+@@ -3351,6 +3383,7 @@
+ 	seqc_t seq;
+ 	const cap_rights_t *haverights;
+ #endif
++	uint8_t flags;
+ 
+ 	fdt = fdp->fd_files;
+ 	if (__predict_false((u_int)fd >= fdt->fdt_nfiles)) {
+@@ -3362,8 +3395,10 @@
+ 	fde = &fdt->fdt_ofiles[fd];
+ 	haverights = cap_rights_fde_inline(fde);
+ 	fp = fde->fde_file;
++	flags = fde->fde_flags;
+ #else
+ 	fp = fdt->fdt_ofiles[fd].fde_file;
++	flags = fdt->fdt_ofiles[fd].fde_flags;
+ #endif
+ 	if (__predict_false(fp == NULL))
+ 		goto out_fallback;
+@@ -3387,12 +3422,21 @@
+ #endif
+ 		goto out_fdrop;
+ 	*fpp = fp;
++	if (flagsp != NULL)
++		*flagsp = flags;
+ 	return (0);
+ out_fdrop:
+ 	fdrop(fp, curthread);
+ out_fallback:
+ 	*fpp = NULL;
+-	return (fget_unlocked_seq(fdp, fd, needrightsp, fpp, NULL));
++	return (fget_unlocked_seq(fdp, fd, needrightsp, flagsp, fpp, NULL));
++}
++
++int
++fget_unlocked(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
++    struct file **fpp)
++{
++	return (fget_unlocked_flags(fdp, fd, needrightsp, NULL, fpp));
+ }
+ 
+ /*
+@@ -3406,7 +3450,7 @@
+  */
+ #ifdef	CAPABILITIES
+ int
+-fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
++fget_only_user(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
+     struct file **fpp)
+ {
+ 	const struct filedescent *fde;
+@@ -3436,7 +3480,7 @@
+ }
+ #else
+ int
+-fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
++fget_only_user(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
+     struct file **fpp)
+ {
+ 	struct file *fp;
+@@ -3472,7 +3516,7 @@
+  */
+ static __inline int
+ _fget(struct thread *td, int fd, struct file **fpp, int flags,
+-    cap_rights_t *needrightsp)
++    const cap_rights_t *needrightsp)
+ {
+ 	struct filedesc *fdp;
+ 	struct file *fp;
+@@ -3520,15 +3564,15 @@
+ }
+ 
+ int
+-fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
++fget(struct thread *td, int fd, const cap_rights_t *rightsp, struct file **fpp)
+ {
+ 
+ 	return (_fget(td, fd, fpp, 0, rightsp));
+ }
+ 
+ int
+-fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, vm_prot_t *maxprotp,
+-    struct file **fpp)
++fget_mmap(struct thread *td, int fd, const cap_rights_t *rightsp,
++    vm_prot_t *maxprotp, struct file **fpp)
+ {
+ 	int error;
+ #ifndef CAPABILITIES
+@@ -3546,7 +3590,7 @@
+ 	fdp = td->td_proc->p_fd;
+ 	MPASS(cap_rights_is_set(rightsp, CAP_MMAP));
+ 	for (;;) {
+-		error = fget_unlocked_seq(fdp, fd, rightsp, &fp, &seq);
++		error = fget_unlocked_seq(fdp, fd, rightsp, NULL, &fp, &seq);
+ 		if (__predict_false(error != 0))
+ 			return (error);
+ 		if (__predict_false(fp->f_ops == &badfileops)) {
+@@ -3571,22 +3615,24 @@
+ }
+ 
+ int
+-fget_read(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
++fget_read(struct thread *td, int fd, const cap_rights_t *rightsp,
++    struct file **fpp)
+ {
+ 
+ 	return (_fget(td, fd, fpp, FREAD, rightsp));
+ }
+ 
+ int
+-fget_write(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
++fget_write(struct thread *td, int fd, const cap_rights_t *rightsp,
++    struct file **fpp)
+ {
+ 
+ 	return (_fget(td, fd, fpp, FWRITE, rightsp));
+ }
+ 
+ int
+-fget_fcntl(struct thread *td, int fd, cap_rights_t *rightsp, int needfcntl,
+-    struct file **fpp)
++fget_fcntl(struct thread *td, int fd, const cap_rights_t *rightsp,
++    int needfcntl, struct file **fpp)
+ {
+ 	struct filedesc *fdp = td->td_proc->p_fd;
+ #ifndef CAPABILITIES
+@@ -3599,7 +3645,7 @@
+ 	*fpp = NULL;
+ 	MPASS(cap_rights_is_set(rightsp, CAP_FCNTL));
+ 	for (;;) {
+-		error = fget_unlocked_seq(fdp, fd, rightsp, &fp, &seq);
++		error = fget_unlocked_seq(fdp, fd, rightsp, NULL, &fp, &seq);
+ 		if (error != 0)
+ 			return (error);
+ 		error = cap_fcntl_check(fdp, fd, needfcntl);
+@@ -3624,7 +3670,7 @@
+  * XXX: what about the unused flags ?
+  */
+ static __inline int
+-_fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp,
++_fgetvp(struct thread *td, int fd, int flags, const cap_rights_t *needrightsp,
+     struct vnode **vpp)
+ {
+ 	struct file *fp;
+@@ -3646,21 +3692,22 @@
+ }
+ 
+ int
+-fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
++fgetvp(struct thread *td, int fd, const cap_rights_t *rightsp,
++    struct vnode **vpp)
+ {
+ 
+ 	return (_fgetvp(td, fd, 0, rightsp, vpp));
+ }
+ 
+ int
+-fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp,
++fgetvp_rights(struct thread *td, int fd, const cap_rights_t *needrightsp,
+     struct filecaps *havecaps, struct vnode **vpp)
+ {
+ 	struct filecaps caps;
+ 	struct file *fp;
+ 	int error;
+ 
+-	error = fget_cap(td, fd, needrightsp, &fp, &caps);
++	error = fget_cap(td, fd, needrightsp, NULL, &fp, &caps);
+ 	if (error != 0)
+ 		return (error);
+ 	if (fp->f_ops == &badfileops) {
+@@ -3685,14 +3732,16 @@
+ }
+ 
+ int
+-fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
++fgetvp_read(struct thread *td, int fd, const cap_rights_t *rightsp,
++    struct vnode **vpp)
+ {
+ 
+ 	return (_fgetvp(td, fd, FREAD, rightsp, vpp));
+ }
+ 
+ int
+-fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
++fgetvp_exec(struct thread *td, int fd, const cap_rights_t *rightsp,
++    struct vnode **vpp)
+ {
+ 
+ 	return (_fgetvp(td, fd, FEXEC, rightsp, vpp));
+@@ -3700,7 +3749,7 @@
+ 
+ #ifdef notyet
+ int
+-fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp,
++fgetvp_write(struct thread *td, int fd, const cap_rights_t *rightsp,
+     struct vnode **vpp)
+ {
+ 
+--- sys/kern/sys_procdesc.c.orig
++++ sys/kern/sys_procdesc.c
+@@ -121,7 +121,7 @@
+  * died.
+  */
+ int
+-procdesc_find(struct thread *td, int fd, cap_rights_t *rightsp,
++procdesc_find(struct thread *td, int fd, const cap_rights_t *rightsp,
+     struct proc **p)
+ {
+ 	struct procdesc *pd;
+@@ -168,7 +168,8 @@
+  * Retrieve the PID associated with a process descriptor.
+  */
+ int
+-kern_pdgetpid(struct thread *td, int fd, cap_rights_t *rightsp, pid_t *pidp)
++kern_pdgetpid(struct thread *td, int fd, const cap_rights_t *rightsp,
++    pid_t *pidp)
+ {
+ 	struct file *fp;
+ 	int error;
+--- sys/kern/uipc_mqueue.c.orig
++++ sys/kern/uipc_mqueue.c
+@@ -2160,13 +2160,14 @@
+ 	return (error);
+ }
+ 
+-typedef int (*_fgetf)(struct thread *, int, cap_rights_t *, struct file **);
++typedef int (*_fgetf)(struct thread *, int, const cap_rights_t *,
++    struct file **);
+ 
+ /*
+  * Get message queue by giving file slot
+  */
+ static int
+-_getmq(struct thread *td, int fd, cap_rights_t *rightsp, _fgetf func,
++_getmq(struct thread *td, int fd, const cap_rights_t *rightsp, _fgetf func,
+        struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq)
+ {
+ 	struct mqfs_node *pn;
+--- sys/kern/uipc_sem.c.orig
++++ sys/kern/uipc_sem.c
+@@ -123,8 +123,8 @@
+ 		    semid_t *semidp, mode_t mode, unsigned int value,
+ 		    int flags, int compat32);
+ static void	ksem_drop(struct ksem *ks);
+-static int	ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
+-    struct file **fpp);
++static int	ksem_get(struct thread *td, semid_t id,
++		    const cap_rights_t *rightsp, struct file **fpp);
+ static struct ksem *ksem_hold(struct ksem *ks);
+ static void	ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
+ static struct ksem *ksem_lookup(char *path, Fnv32_t fnv);
+@@ -588,7 +588,7 @@
+ }
+ 
+ static int
+-ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
++ksem_get(struct thread *td, semid_t id, const cap_rights_t *rightsp,
+     struct file **fpp)
+ {
+ 	struct ksem *ks;
+--- sys/kern/uipc_syscalls.c.orig
++++ sys/kern/uipc_syscalls.c
+@@ -91,13 +91,13 @@
+  * A reference on the file entry is held upon returning.
+  */
+ int
+-getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
++getsock_cap(struct thread *td, int fd, const cap_rights_t *rightsp,
+     struct file **fpp, u_int *fflagp, struct filecaps *havecapsp)
+ {
+ 	struct file *fp;
+ 	int error;
+ 
+-	error = fget_cap(td, fd, rightsp, &fp, havecapsp);
++	error = fget_cap(td, fd, rightsp, NULL, &fp, havecapsp);
+ 	if (error != 0)
+ 		return (error);
+ 	if (fp->f_type != DTYPE_SOCKET) {
+@@ -727,7 +727,7 @@
+ 	struct uio auio;
+ 	struct iovec *iov;
+ 	struct socket *so;
+-	cap_rights_t *rights;
++	const cap_rights_t *rights;
+ #ifdef KTRACE
+ 	struct uio *ktruio = NULL;
+ #endif
+--- sys/kern/uipc_usrreq.c.orig
++++ sys/kern/uipc_usrreq.c
+@@ -57,7 +57,6 @@
+  *	need a proper out-of-band
+  */
+ 
+-#include <sys/cdefs.h>
+ #include "opt_ddb.h"
+ 
+ #include <sys/param.h>
+@@ -67,6 +66,7 @@
+ #include <sys/fcntl.h>
+ #include <sys/file.h>
+ #include <sys/filedesc.h>
++#include <sys/jail.h>
+ #include <sys/kernel.h>
+ #include <sys/lock.h>
+ #include <sys/malloc.h>
+@@ -1993,22 +1993,34 @@
+ 	free(fdep[0], M_FILECAPS);
+ }
+ 
++static bool
++restrict_rights(struct file *fp, struct thread *td)
++{
++	struct prison *prison1, *prison2;
++
++	prison1 = fp->f_cred->cr_prison;
++	prison2 = td->td_ucred->cr_prison;
++	return (prison1 != prison2 && prison1->pr_root != prison2->pr_root &&
++	    prison2 != &prison0);
++}
++
+ static int
+ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags)
*** 1797 LINES SKIPPED ***


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?699dd13d.3143f.108afe9e>