git: 350ba9672a7f - main - unix: Set O_RESOLVE_BENEATH on fds transferred between jails
- Reply: Konstantin Belousov : "Re: git: 350ba9672a7f - main - unix: Set O_RESOLVE_BENEATH on fds transferred between jails"
- Reply: Kristof Provost : "Re: git: 350ba9672a7f - main - unix: Set O_RESOLVE_BENEATH on fds transferred between jails"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 24 Jun 2025 21:04:35 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=350ba9672a7f4f16e30534a603df577dfd083b3f
commit 350ba9672a7f4f16e30534a603df577dfd083b3f
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-06-24 20:05:37 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-06-24 21:04:24 +0000
unix: Set O_RESOLVE_BENEATH on fds transferred between jails
If a pair of jails with different filesystem roots is able to exchange
SCM_RIGHTS messages (e.g., using a unix socket in a shared nullfs
mount), a process in one jail can open a directory outside of the root
of the second jail and then pass the fd to that second jail, allowing
the receiving process to escape the jail chroot.
Address this using the new FD_RESOLVE_BENEATH flag. When externalizing
an SCM_RIGHTS message into the receiving process, automatically set this
flag on all new fds where a jail boundary is crossed. This ensures that
the receiver cannot do more than access files underneath the directory;
in particular, the received fd cannot be used to access vnodes not
accessible by the sender.
PR: 262179
Reviewed by: kib
MFC after: 3 weeks
Differential Revision: https://reviews.freebsd.org/D50371
---
sys/amd64/conf/SYZKALLER | 5 +++++
sys/kern/uipc_usrreq.c | 31 +++++++++++++++++++++++--------
2 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/sys/amd64/conf/SYZKALLER b/sys/amd64/conf/SYZKALLER
new file mode 100644
index 000000000000..965841313616
--- /dev/null
+++ b/sys/amd64/conf/SYZKALLER
@@ -0,0 +1,5 @@
+include GENERIC-KASAN
+ident SYZKALLER
+
+options COVERAGE
+options KCOV
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 3f6535567e9d..72bd0246db11 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -56,7 +56,6 @@
* need a proper out-of-band
*/
-#include <sys/cdefs.h>
#include "opt_ddb.h"
#include <sys/param.h>
@@ -66,6 +65,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>
@@ -3437,22 +3437,34 @@ unp_freerights(struct filedescent **fdep, int fdcount)
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)
{
struct thread *td = curthread; /* XXX */
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
- int i;
int *fdp;
struct filedesc *fdesc = td->td_proc->p_fd;
struct filedescent **fdep;
void *data;
socklen_t clen = control->m_len, datalen;
- int error, newfds;
+ int error, fdflags, newfds;
u_int newlen;
UNP_LINK_UNLOCK_ASSERT();
+ fdflags = (flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
+
error = 0;
if (controlp != NULL) /* controlp == NULL => free control messages */
*controlp = NULL;
@@ -3494,11 +3506,14 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags)
*controlp = NULL;
goto next;
}
- for (i = 0; i < newfds; i++, fdp++) {
- _finstall(fdesc, fdep[i]->fde_file, *fdp,
- (flags & MSG_CMSG_CLOEXEC) != 0 ? O_CLOEXEC : 0,
- &fdep[i]->fde_caps);
- unp_externalize_fp(fdep[i]->fde_file);
+ for (int i = 0; i < newfds; i++, fdp++) {
+ struct file *fp;
+
+ fp = fdep[i]->fde_file;
+ _finstall(fdesc, fp, *fdp, fdflags |
+ (restrict_rights(fp, td) ?
+ O_RESOLVE_BENEATH : 0), &fdep[i]->fde_caps);
+ unp_externalize_fp(fp);
}
/*