mirror of
https://github.com/opnsense/src.git
synced 2026-04-24 23:57:30 -04:00
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. Approved by: so Security: FreeBSD-SA-26:04.jail Security: CVE-2025-15576 PR: 262179 Reviewed by: kib MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D50371 (cherry picked from commit 350ba9672a7f4f16e30534a603df577dfd083b3f) (cherry picked from commit 3ad3ab5f9b6e91efc923bae9799697a823eb7227)
This commit is contained in:
parent
9a9303e4b9
commit
6d73cae873
2 changed files with 28 additions and 8 deletions
5
sys/amd64/conf/SYZKALLER
Normal file
5
sys/amd64/conf/SYZKALLER
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
include GENERIC-KASAN
|
||||
ident SYZKALLER
|
||||
|
||||
options COVERAGE
|
||||
options KCOV
|
||||
|
|
@ -58,7 +58,6 @@
|
|||
* need a proper out-of-band
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include "opt_ddb.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
|
@ -68,6 +67,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>
|
||||
|
|
@ -2433,22 +2433,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;
|
||||
|
|
@ -2490,11 +2502,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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue