Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162819099
D50371.id155572.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D50371.id155572.diff
View Options
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
--- a/sys/fs/fdescfs/fdesc_vnops.c
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -639,7 +639,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;
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -109,7 +109,8 @@
static void fdunused(struct filedesc *fdp, int fd);
static void fdused(struct filedesc *fdp, int fd);
static int fget_unlocked_seq(struct thread *td, int fd,
- cap_rights_t *needrightsp, struct file **fpp, seqc_t *seqp);
+ 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,
@@ -2163,7 +2164,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_BENEATH : 0);
if (fcaps != NULL)
filecaps_move(fcaps, &fde->fde_caps);
else
@@ -2910,7 +2912,7 @@
#ifdef CAPABILITIES
int
-fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp,
+fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp, uint8_t *flagsp,
struct file **fpp, struct filecaps *havecapsp)
{
struct filedesc *fdp = td->td_proc->p_fd;
@@ -2920,7 +2922,8 @@
*fpp = NULL;
for (;;) {
- error = fget_unlocked_seq(td, fd, needrightsp, &fp, &seq);
+ error = fget_unlocked_seq(td, fd, needrightsp, flagsp, &fp,
+ &seq);
if (error != 0)
return (error);
@@ -2950,11 +2953,11 @@
}
#else
int
-fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp,
+fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp, uint8_t *flagsp,
struct file **fpp, struct filecaps *havecapsp)
{
int error;
- error = fget_unlocked(td, fd, needrightsp, fpp);
+ error = fget_unlocked(td, fd, needrightsp, flagsp, fpp);
if (havecapsp != NULL && error == 0)
filecaps_fill(havecapsp);
@@ -3151,13 +3154,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)) {
@@ -3175,6 +3180,10 @@
*/
if ((fp->f_flag & FSEARCH) != 0)
cnp->cn_flags |= NOEXECCHECK;
+ if ((flags & UF_BENEATH) != 0) {
+ cnp->cn_flags |= RBENEATH;
+ ndp->ni_resflags |= NIRES_BENEATH;
+ }
fdrop(fp, td);
#ifdef CAPABILITIES
@@ -3222,7 +3231,7 @@
#ifdef CAPABILITIES
static int
fget_unlocked_seq(struct thread *td, int fd, cap_rights_t *needrightsp,
- struct file **fpp, seqc_t *seqp)
+ uint8_t *flagsp, struct file **fpp, seqc_t *seqp)
{
struct filedesc *fdp;
const struct filedescent *fde;
@@ -3231,6 +3240,7 @@
seqc_t seq;
cap_rights_t haverights;
int error;
+ uint8_t flags;
fdp = td->td_proc->p_fd;
fdt = fdp->fd_files;
@@ -3241,6 +3251,7 @@
seq = seqc_read_notmodify(fd_seqc(fdt, fd));
fde = &fdt->fdt_ofiles[fd];
haverights = *cap_rights_fde_inline(fde);
+ flags = fde->fde_flags;
fp = fde->fde_file;
if (__predict_false(fp == NULL)) {
if (seqc_consistent(fd_seqc(fdt, fd), seq))
@@ -3270,19 +3281,21 @@
fdrop(fp, td);
}
*fpp = fp;
- if (seqp != NULL) {
+ if (flagsp != NULL)
+ *flagsp = flags;
+ if (seqp != NULL)
*seqp = seq;
- }
return (0);
}
#else
static int
fget_unlocked_seq(struct thread *td, int fd, cap_rights_t *needrightsp,
- struct file **fpp, seqc_t *seqp __unused)
+ uint8_t *flagsp, struct file **fpp, seqc_t *seqp __unused)
{
struct filedesc *fdp;
const struct fdescenttbl *fdt;
struct file *fp;
+ uint8_t flags;
fdp = td->td_proc->p_fd;
fdt = fdp->fd_files;
@@ -3290,6 +3303,7 @@
return (EBADF);
for (;;) {
+ flags = fdt->fdt_ofiles[fd].fde_flags;
fp = fdt->fdt_ofiles[fd].fde_file;
if (__predict_false(fp == NULL))
return (EBADF);
@@ -3307,6 +3321,8 @@
break;
fdrop(fp, td);
}
+ if (flagsp != NULL)
+ *flagsp = flags;
*fpp = fp;
return (0);
}
@@ -3375,7 +3391,7 @@
fdrop(fp, td);
out_fallback:
*fpp = NULL;
- return (fget_unlocked_seq(td, fd, needrightsp, fpp, NULL));
+ return (fget_unlocked_seq(td, fd, needrightsp, NULL, fpp, NULL));
}
/*
@@ -3527,7 +3543,7 @@
fdp = td->td_proc->p_fd;
MPASS(cap_rights_is_set(rightsp, CAP_MMAP));
for (;;) {
- error = fget_unlocked_seq(td, fd, rightsp, &fp, &seq);
+ error = fget_unlocked_seq(td, fd, rightsp, NULL, &fp, &seq);
if (__predict_false(error != 0))
return (error);
if (__predict_false(fp->f_ops == &badfileops)) {
@@ -3580,7 +3596,7 @@
*fpp = NULL;
MPASS(cap_rights_is_set(rightsp, CAP_FCNTL));
for (;;) {
- error = fget_unlocked_seq(td, fd, rightsp, &fp, &seq);
+ error = fget_unlocked_seq(td, fd, rightsp, NULL, &fp, &seq);
if (error != 0)
return (error);
error = cap_fcntl_check(fdp, fd, needfcntl);
@@ -3641,7 +3657,7 @@
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) {
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -91,7 +91,7 @@
struct file *fp;
int error;
- error = fget_cap(td, fd, rightsp, &fp, havecapsp);
+ error = fget_cap(td, fd, rightsp, NULL, &fp, havecapsp);
if (__predict_false(error != 0))
return (error);
if (__predict_false(fp->f_type != DTYPE_SOCKET)) {
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
--- 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>
@@ -3409,22 +3409,33 @@
free(fdep[0], M_FILECAPS);
}
+static bool
+restrict_caps(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);
+}
+
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;
@@ -3466,11 +3477,20 @@
*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 filecaps caps;
+ struct file *fp;
+ bool xprison;
+
+ fp = fdep[i]->fde_file;
+ caps = fdep[i]->fde_caps;
+ xprison = restrict_caps(fp, td);
+ if (xprison)
+ cap_rights_clear(&caps.fc_rights,
+ CAP_FCHDIR, CAP_FCHROOT);
+ _finstall(fdesc, fp, *fdp, fdflags |
+ (xprison ? O_RESOLVE_BENEATH : 0), &caps);
+ unp_externalize_fp(fp);
}
/*
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1310,6 +1310,10 @@
else
#endif
fcaps = NULL;
+ if ((nd.ni_resflags & NIRES_BENEATH) != 0)
+ flags |= O_RESOLVE_BENEATH;
+ else
+ flags &= ~O_RESOLVE_BENEATH;
error = finstall_refed(td, fp, &indx, flags, fcaps);
/* On success finstall_refed() consumes fcaps. */
if (error != 0) {
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -148,6 +148,7 @@
* Per-process open flags.
*/
#define UF_EXCLOSE 0x01 /* auto-close on exec */
+#define UF_BENEATH 0x02 /* lookups must be beneath this dir */
#ifdef _KERNEL
@@ -284,7 +285,7 @@
int fget_cap_noref(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
struct file **fpp, struct filecaps *havecapsp);
int fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp,
- struct file **fpp, struct filecaps *havecapsp);
+ uint8_t *flagsp, struct file **fpp, struct filecaps *havecapsp);
/* Return a referenced file from an unlocked descriptor. */
int fget_unlocked(struct thread *td, int fd, cap_rights_t *needrightsp,
struct file **fpp);
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -195,6 +195,7 @@
#define NIRES_ABS 0x00000001 /* Path was absolute */
#define NIRES_STRICTREL 0x00000002 /* Restricted lookup result */
#define NIRES_EMPTYPATH 0x00000004 /* EMPTYPATH used */
+#define NIRES_BENEATH 0x00000008 /* O_RESOLVE_BENEATH is to be inherited */
/*
* Flags in ni_lcf, valid for the duration of the namei call.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jul 18, 5:30 AM (5 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35190356
Default Alt Text
D50371.id155572.diff (9 KB)
Attached To
Mode
D50371: unix: Restrict dirfds exchanged between jails with a different root
Attached
Detach File
Event Timeline
Log In to Comment