Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Apr 2019 20:42:15 +0000 (UTC)
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r345781 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs
Message-ID:  <201904012042.x31KgFqO050033@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: asomers
Date: Mon Apr  1 20:42:15 2019
New Revision: 345781
URL: https://svnweb.freebsd.org/changeset/base/345781

Log:
  fusefs: send FUSE_OPEN for every open(2) with unique credentials
  
  By default, FUSE performs authorization in the server.  That means that it's
  insecure for the client to reuse FUSE file handles between different users,
  groups, or processes.  Linux handles this problem by creating a different
  FUSE file handle for every file descriptor.  FreeBSD can't, due to
  differences in our VFS design.
  
  This commit adds credential information to each fuse_filehandle.  During
  open(2), fusefs will now only reuse a file handle if it matches the exact
  same access mode, pid, uid, and gid of the calling process.
  
  PR:		236844
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/fuse2/sys/fs/fuse/fuse_file.c
  projects/fuse2/sys/fs/fuse/fuse_file.h
  projects/fuse2/sys/fs/fuse/fuse_io.c
  projects/fuse2/sys/fs/fuse/fuse_io.h
  projects/fuse2/sys/fs/fuse/fuse_node.c
  projects/fuse2/sys/fs/fuse/fuse_node.h
  projects/fuse2/sys/fs/fuse/fuse_vnops.c
  projects/fuse2/tests/sys/fs/fusefs/allow_other.cc
  projects/fuse2/tests/sys/fs/fusefs/open.cc

Modified: projects/fuse2/sys/fs/fuse/fuse_file.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.c	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/sys/fs/fuse/fuse_file.c	Mon Apr  1 20:42:15 2019	(r345781)
@@ -109,11 +109,6 @@ fuse_filehandle_open(struct vnode *vp, fufh_type_t fuf
 	int oflags = 0;
 	int op = FUSE_OPEN;
 
-	if (fuse_filehandle_valid(vp, fufh_type)) {
-		panic("FUSE: filehandle_open called despite valid fufh (type=%d)",
-		    fufh_type);
-		/* NOTREACHED */
-	}
 	/*
 	 * Note that this means we are effectively FILTERING OUT open() flags.
 	 */
@@ -140,7 +135,8 @@ fuse_filehandle_open(struct vnode *vp, fufh_type_t fuf
 	}
 	foo = fdi.answ;
 
-	fuse_filehandle_init(vp, fufh_type, fufhp, foo->fh);
+	fuse_filehandle_init(vp, fufh_type, fufhp, td->td_proc->p_pid, cred,
+		foo->fh);
 
 	fuse_vnode_open(vp, foo->open_flags, td);
 
@@ -181,37 +177,66 @@ out:
 	return err;
 }
 
-int
-fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type)
-{
-	return (0 == fuse_filehandle_get(vp, fufh_type, NULL));
-}
-
 /*
  * Check for a valid file handle, first the type requested, but if that
  * isn't valid, try for FUFH_RDWR.
- * Return the FUFH type that is valid or FUFH_INVALID if there are none.
- * This is a variant of fuse_filehandle_valid() analogous to
- * fuse_filehandle_getrw().
+ * Return true if there is any file handle with the correct credentials and
+ * a fufh type that includes the provided one.
+ * A pid of 0 means "don't care"
  */
-fufh_type_t
-fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type)
+bool
+fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type,
+	struct ucred *cred, pid_t pid)
 {
-	if (fuse_filehandle_get(vp, fufh_type, NULL) == 0)
-		return (fufh_type);
-	if (fuse_filehandle_get(vp, FUFH_RDWR, NULL) == 0)
-		return (FUFH_RDWR);
-	return (FUFH_INVALID);
+	struct fuse_vnode_data *fvdat = VTOFUD(vp);
+	struct fuse_filehandle *fufh;
+
+	/* 
+	 * Unlike fuse_filehandle_get, we want to search for a filehandle with
+	 * the exact cred, and no fallback
+	 */
+	LIST_FOREACH(fufh, &fvdat->handles, next) {
+		if (fufh->flags == fufh_type &&
+		    fufh->uid == cred->cr_uid &&
+		    fufh->gid == cred->cr_rgid &&
+		    (pid == 0 || fufh->pid == pid))
+			return true;
+	}
+
+	if (fufh_type == FUFH_EXEC)
+		return false;
+
+	/* Fallback: find a RDWR list entry with the right cred */
+	LIST_FOREACH(fufh, &fvdat->handles, next) {
+		if (fufh->flags == FUFH_RDWR &&
+		    fufh->uid == cred->cr_uid &&
+		    fufh->gid == cred->cr_rgid &&
+		    (pid == 0 || fufh->pid == pid))
+			return true;
+	}
+
+	return false;
 }
 
 int
 fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
-    struct fuse_filehandle **fufhp)
+    struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
 {
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct fuse_filehandle *fufh;
 
-	/* TODO: Find a list entry with the same flags, pid, gid, and uid */
+	if (cred == NULL)
+		goto fallback;
+
+	LIST_FOREACH(fufh, &fvdat->handles, next) {
+		if (fufh->flags == fufh_type &&
+		    fufh->uid == cred->cr_uid &&
+		    fufh->gid == cred->cr_rgid &&
+		    (pid == 0 || fufh->pid == pid))
+			goto found;
+	}
+
+fallback:
 	/* Fallback: find a list entry with the right flags */
 	LIST_FOREACH(fufh, &fvdat->handles, next) {
 		if (fufh->flags == fufh_type)
@@ -220,6 +245,8 @@ fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh
 
 	if (fufh == NULL)
 		return EBADF;
+
+found:
 	if (fufhp != NULL)
 		*fufhp = fufh;
 	return 0;
@@ -227,19 +254,20 @@ fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh
 
 int
 fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
-    struct fuse_filehandle **fufhp)
+    struct fuse_filehandle **fufhp, struct ucred *cred, pid_t pid)
 {
 	int err;
 
-	err = fuse_filehandle_get(vp, fufh_type, fufhp);
+	err = fuse_filehandle_get(vp, fufh_type, fufhp, cred, pid);
 	if (err)
-		err = fuse_filehandle_get(vp, FUFH_RDWR, fufhp);
+		err = fuse_filehandle_get(vp, FUFH_RDWR, fufhp, cred, pid);
 	return err;
 }
 
 void
 fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
-    struct fuse_filehandle **fufhp, uint64_t fh_id)
+    struct fuse_filehandle **fufhp, pid_t pid, struct ucred *cred,
+    uint64_t fh_id)
 {
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct fuse_filehandle *fufh;
@@ -249,7 +277,10 @@ fuse_filehandle_init(struct vnode *vp, fufh_type_t fuf
 	MPASS(fufh != NULL);
 	fufh->fh_id = fh_id;
 	fufh->flags = fufh_type;
-	/* TODO: initialize fufh credentials and open flags */
+	fufh->gid = cred->cr_rgid;
+	fufh->uid = cred->cr_uid;
+	fufh->pid = pid;
+	/* TODO: initialize open flags */
 	if (!FUFH_IS_VALID(fufh)) {
 		panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
 	}

Modified: projects/fuse2/sys/fs/fuse/fuse_file.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_file.h	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/sys/fs/fuse/fuse_file.h	Mon Apr  1 20:42:15 2019	(r345781)
@@ -78,6 +78,56 @@ typedef enum fufh_type {
 	FUFH_EXEC    = O_EXEC,
 } fufh_type_t;
 
+/*
+ * FUSE File Handles
+ *
+ * The FUSE protocol says that a server may assign a unique 64-bit file handle
+ * every time that a file is opened.  Effectively, that's once for each file
+ * descriptor.
+ *
+ * Unfortunately, the VFS doesn't help us here.  VOPs don't have a
+ * struct file* argument.  fileops do, but many syscalls bypass the fileops
+ * layer and go straight to a vnode.  Some, like writing from cache, can't
+ * track a file handle even in theory.  The entire concept of the file handle
+ * is a product of FUSE's Linux origins; Linux lacks vnodes and almost every
+ * file system operation takes a struct file* argument.
+ *
+ * Since FreeBSD's VFS is more file descriptor-agnostic, we must store FUSE
+ * filehandles in the vnode.  One option would be to only store a single file
+ * handle and never open FUSE files concurrently.  That's what NetBSD does.
+ * But that violates FUSE's security model.  FUSE expects the server to do all
+ * authorization (except when mounted with -o default_permissions).  In order
+ * to do that, the server needs us to send FUSE_OPEN every time somebody opens
+ * a new file descriptor.
+ *
+ * Another option would be to never open FUSE files concurrently, but send a
+ * FUSE_ACCESS prior to every open after the first.  That would give the server
+ * the opportunity to authorize the access.  Unfortunately, the FUSE protocol
+ * makes ACCESS optional.  File systems that don't implement it are assumed to
+ * authorize everything.  A survey of 32 fuse file systems showed that only 14
+ * implemented access.  Among the laggards were a few that really ought to be
+ * doing server-side authorization.
+ *
+ * So we do something hacky, similar to what OpenBSD, Illumos, and OSXFuse do.
+ * we store a list of file handles, one for each combination of vnode, uid,
+ * gid, pid, and access mode.  When opening a file, we first check whether
+ * there's already a matching file handle.  If so, we reuse it.  If not, we
+ * send FUSE_OPEN and create a new file handle.  That minimizes the number of
+ * open file handles while still allowing the server to authorize stuff.
+ *
+ * VOPs that need a file handle search through the list for a close match.
+ * They can't be guaranteed of finding an exact match because, for example, a
+ * process may have changed its UID since opening the file.  Also, most VOPs
+ * don't know exactly what permission they need.  Is O_RDWR required or is
+ * O_RDONLY good enough?  So the file handle we end up using may not be exactly
+ * the one we're supposed to use with that file descriptor.  But if the FUSE
+ * file system isn't too picky, it will work.  (FWIW even Linux sometimes
+ * guesses the file handle, during writes from cache or most SETATTR
+ * operations).
+ *
+ * I suspect this mess is part of the reason why neither NFS nor 9P have an
+ * equivalent of FUSE file handles.
+ */
 struct fuse_filehandle {
 	LIST_ENTRY(fuse_filehandle) next;
 
@@ -132,15 +182,18 @@ fuse_filehandle_xlate_to_oflags(fufh_type_t type)
 	return oflags;
 }
 
-int fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type);
-fufh_type_t fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type);
+bool fuse_filehandle_validrw(struct vnode *vp, fufh_type_t fufh_type,
+	struct ucred *cred, pid_t pid);
 int fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
-                        struct fuse_filehandle **fufhp);
+                        struct fuse_filehandle **fufhp, struct ucred *cred,
+			pid_t pid);
 int fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
-                          struct fuse_filehandle **fufhp);
+                          struct fuse_filehandle **fufhp, struct ucred *cred,
+			  pid_t pid);
 
 void fuse_filehandle_init(struct vnode *vp, fufh_type_t fufh_type,
-		          struct fuse_filehandle **fufhp, uint64_t fh_id);
+		          struct fuse_filehandle **fufhp, pid_t pid,
+			  struct ucred *cred, uint64_t fh_id);
 int fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type,
                          struct fuse_filehandle **fufhp, struct thread *td,
                          struct ucred *cred);

Modified: projects/fuse2/sys/fs/fuse/fuse_io.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_io.c	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/sys/fs/fuse/fuse_io.c	Mon Apr  1 20:42:15 2019	(r345781)
@@ -111,27 +111,28 @@ fuse_read_directbackend(struct vnode *vp, struct uio *
     struct ucred *cred, struct fuse_filehandle *fufh);
 static int 
 fuse_read_biobackend(struct vnode *vp, struct uio *uio,
-    struct ucred *cred, struct fuse_filehandle *fufh);
+    struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid);
 static int 
 fuse_write_directbackend(struct vnode *vp, struct uio *uio,
     struct ucred *cred, struct fuse_filehandle *fufh, int ioflag);
 static int 
 fuse_write_biobackend(struct vnode *vp, struct uio *uio,
-    struct ucred *cred, struct fuse_filehandle *fufh, int ioflag);
+    struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid);
 
 SDT_PROBE_DEFINE5(fuse, , io, io_dispatch, "struct vnode*", "struct uio*",
 		"int", "struct ucred*", "struct fuse_filehandle*");
 int
 fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
-    struct ucred *cred)
+    struct ucred *cred, pid_t pid)
 {
 	struct fuse_filehandle *fufh;
 	int err, directio;
+	fufh_type_t fufh_type;
 
 	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 
-	err = fuse_filehandle_getrw(vp,
-	    (uio->uio_rw == UIO_READ) ? FUFH_RDONLY : FUFH_WRONLY, &fufh);
+	fufh_type = (uio->uio_rw == UIO_READ) ? FUFH_RDONLY : FUFH_WRONLY;
+	err = fuse_filehandle_getrw(vp, fufh_type, &fufh, cred, pid);
 	if (err) {
 		printf("FUSE: io dispatch: filehandles are closed\n");
 		return err;
@@ -159,7 +160,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in
 		} else {
 			SDT_PROBE2(fuse, , io, trace, 1,
 				"buffered read of vnode");
-			err = fuse_read_biobackend(vp, uio, cred, fufh);
+			err = fuse_read_biobackend(vp, uio, cred, fufh, pid);
 		}
 		break;
 	case UIO_WRITE:
@@ -172,11 +173,13 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in
 		if (directio || fuse_data_cache_mode == FUSE_CACHE_WT) {
 			SDT_PROBE2(fuse, , io, trace, 1,
 				"direct write of vnode");
-			err = fuse_write_directbackend(vp, uio, cred, fufh, ioflag);
+			err = fuse_write_directbackend(vp, uio, cred, fufh,
+				ioflag);
 		} else {
 			SDT_PROBE2(fuse, , io, trace, 1,
 				"buffered write of vnode");
-			err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag);
+			err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag,
+				pid);
 		}
 		break;
 	default:
@@ -191,7 +194,7 @@ SDT_PROBE_DEFINE2(fuse, , io, read_bio_backend_feed, "
 SDT_PROBE_DEFINE3(fuse, , io, read_bio_backend_end, "int", "ssize_t", "int");
 static int
 fuse_read_biobackend(struct vnode *vp, struct uio *uio,
-    struct ucred *cred, struct fuse_filehandle *fufh)
+    struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid)
 {
 	struct buf *bp;
 	daddr_t lbn;
@@ -405,7 +408,7 @@ SDT_PROBE_DEFINE2(fuse, , io, write_biobackend_append_
 
 static int
 fuse_write_biobackend(struct vnode *vp, struct uio *uio,
-    struct ucred *cred, struct fuse_filehandle *fufh, int ioflag)
+    struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid)
 {
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct buf *bp;
@@ -625,7 +628,7 @@ again:
 	} while (uio->uio_resid > 0 && n > 0);
 
 	if (fuse_sync_resize && (fvdat->flag & FN_SIZECHANGE) != 0)
-		fuse_vnode_savesize(vp, cred);
+		fuse_vnode_savesize(vp, cred, pid);
 
 	return (err);
 }
@@ -640,14 +643,18 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
 	struct uio uio;
 	struct iovec io;
 	int error = 0;
+	fufh_type_t fufh_type;
+	/* We don't know the true pid when we're dealing with the cache */
+	pid_t pid = 0;
 
 	const int biosize = fuse_iosize(vp);
 
 	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
 	MPASS(bp->b_iocmd == BIO_READ || bp->b_iocmd == BIO_WRITE);
 
-	error = fuse_filehandle_getrw(vp,
-	    (bp->b_iocmd == BIO_READ) ? FUFH_RDONLY : FUFH_WRONLY, &fufh);
+	fufh_type = bp->b_iocmd == BIO_READ ? FUFH_RDONLY : FUFH_WRONLY;
+	cred = bp->b_iocmd == BIO_READ ? bp->b_rcred : bp->b_wcred;
+	error = fuse_filehandle_getrw(vp, fufh_type, &fufh, cred, pid);
 	if (bp->b_iocmd == BIO_READ && error == EBADF) {
 		/* 
 		 * This may be a read-modify-write operation on a cached file
@@ -655,7 +662,8 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
 		 *
 		 * TODO: eliminate this hacky check once the FUFH table is gone
 		 */
-		error = fuse_filehandle_get(vp, FUFH_WRONLY, &fufh);
+		fufh_type = FUFH_WRONLY;
+		error = fuse_filehandle_get(vp, fufh_type, &fufh, cred, pid);
 	}
 	if (error) {
 		printf("FUSE: strategy: filehandles are closed\n");
@@ -664,7 +672,6 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp)
 		bufdone(bp);
 		return (error);
 	}
-	cred = bp->b_iocmd == BIO_READ ? bp->b_rcred : bp->b_wcred;
 
 	uiop = &uio;
 	uiop->uio_iov = &io;

Modified: projects/fuse2/sys/fs/fuse/fuse_io.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_io.h	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/sys/fs/fuse/fuse_io.h	Mon Apr  1 20:42:15 2019	(r345781)
@@ -61,7 +61,7 @@
 #define _FUSE_IO_H_
 
 int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
-    struct ucred *cred);
+    struct ucred *cred, pid_t pid);
 int fuse_io_strategy(struct vnode *vp, struct buf *bp);
 int fuse_io_flushbuf(struct vnode *vp, int waitfor, struct thread *td);
 int fuse_io_invalbuf(struct vnode *vp, struct thread *td);

Modified: projects/fuse2/sys/fs/fuse/fuse_node.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_node.c	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/sys/fs/fuse/fuse_node.c	Mon Apr  1 20:42:15 2019	(r345781)
@@ -345,7 +345,7 @@ fuse_vnode_open(struct vnode *vp, int32_t fuse_open_fl
 }
 
 int
-fuse_vnode_savesize(struct vnode *vp, struct ucred *cred)
+fuse_vnode_savesize(struct vnode *vp, struct ucred *cred, pid_t pid)
 {
 	struct fuse_vnode_data *fvdat = VTOFUD(vp);
 	struct thread *td = curthread;
@@ -377,7 +377,7 @@ fuse_vnode_savesize(struct vnode *vp, struct ucred *cr
 	fsai->size = fvdat->filesize;
 	fsai->valid |= FATTR_SIZE;
 
-	fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
+	fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh, cred, pid);
 	if (fufh) {
 		fsai->fh = fufh->fh_id;
 		fsai->valid |= FATTR_FH;

Modified: projects/fuse2/sys/fs/fuse/fuse_node.h
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_node.h	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/sys/fs/fuse/fuse_node.h	Mon Apr  1 20:42:15 2019	(r345781)
@@ -126,7 +126,7 @@ void fuse_vnode_open(struct vnode *vp, int32_t fuse_op
 
 int fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred);
 
-int fuse_vnode_savesize(struct vnode *vp, struct ucred *cred);
+int fuse_vnode_savesize(struct vnode *vp, struct ucred *cred, pid_t pid);
 
 int fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize);
 

Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_vnops.c	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/sys/fs/fuse/fuse_vnops.c	Mon Apr  1 20:42:15 2019	(r345781)
@@ -216,6 +216,16 @@ uma_zone_t fuse_pbuf_zone;
 #define fuse_vm_page_lock_queues()	((void)0)
 #define fuse_vm_page_unlock_queues()	((void)0)
 
+/* Get a filehandle for a directory */
+static int
+fuse_filehandle_get_dir(struct vnode *vp, struct fuse_filehandle **fufhp,
+	struct ucred *cred, pid_t pid)
+{
+	if (fuse_filehandle_get(vp, FUFH_RDONLY, fufhp, cred, pid) == 0)
+		return 0;
+	return fuse_filehandle_get(vp, FUFH_EXEC, fufhp, cred, pid);
+}
+
 /*
     struct vnop_access_args {
 	struct vnode *a_vp;
@@ -278,6 +288,8 @@ fuse_vnop_close(struct vop_close_args *ap)
 	struct vnode *vp = ap->a_vp;
 	struct ucred *cred = ap->a_cred;
 	int fflag = ap->a_fflag;
+	struct thread *td = ap->a_td;
+	pid_t pid = td->td_proc->p_pid;
 
 	if (fuse_isdeadfs(vp)) {
 		return 0;
@@ -285,8 +297,7 @@ fuse_vnop_close(struct vop_close_args *ap)
 	if (vnode_isdir(vp)) {
 		struct fuse_filehandle *fufh;
 
-		if ((fuse_filehandle_get(vp, O_RDONLY, &fufh) == 0) ||
-		    (fuse_filehandle_get(vp, O_EXEC, &fufh) == 0))
+		if (fuse_filehandle_get_dir(vp, &fufh, cred, pid) == 0)
 			fuse_filehandle_close(vp, fufh, NULL, cred);
 		return 0;
 	}
@@ -295,7 +306,7 @@ fuse_vnop_close(struct vop_close_args *ap)
 	}
 	/* TODO: close the file handle, if we're sure it's no longer used */
 	if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
-		fuse_vnode_savesize(vp, cred);
+		fuse_vnode_savesize(vp, cred, td->td_proc->p_pid);
 	}
 	return 0;
 }
@@ -432,7 +443,8 @@ fuse_vnop_create(struct vop_create_args *ap)
 	}
 	ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
 
-	fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, foo->fh);
+	fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, td->td_proc->p_pid, cred,
+		foo->fh);
 	fuse_vnode_open(*vpp, foo->open_flags, td);
 	cache_purge_negative(dvp);
 
@@ -597,7 +609,7 @@ fuse_vnop_inactive(struct vop_inactive_args *ap)
 	LIST_FOREACH_SAFE(fufh, &fvdat->handles, next, fufh_tmp) {
 		if (need_flush && vp->v_type == VREG) {
 			if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
-				fuse_vnode_savesize(vp, NULL);
+				fuse_vnode_savesize(vp, NULL, 0);
 			}
 			if (fuse_data_cache_invalidate ||
 			    (fvdat->flag & FN_REVOKED) != 0)
@@ -1194,6 +1206,7 @@ fuse_vnop_open(struct vop_open_args *ap)
 	int mode = ap->a_mode;
 	struct thread *td = ap->a_td;
 	struct ucred *cred = ap->a_cred;
+	pid_t pid = td->td_proc->p_pid;
 
 	fufh_type_t fufh_type;
 	struct fuse_vnode_data *fvdat;
@@ -1209,7 +1222,7 @@ fuse_vnop_open(struct vop_open_args *ap)
 
 	fufh_type = fuse_filehandle_xlate_from_fflags(mode);
 
-	if (fuse_filehandle_validrw(vp, fufh_type) != FUFH_INVALID) {
+	if (fuse_filehandle_validrw(vp, fufh_type, cred, pid)) {
 		fuse_vnode_open(vp, 0, td);
 		return 0;
 	}
@@ -1257,6 +1270,7 @@ fuse_vnop_read(struct vop_read_args *ap)
 	struct uio *uio = ap->a_uio;
 	int ioflag = ap->a_ioflag;
 	struct ucred *cred = ap->a_cred;
+	pid_t pid = curthread->td_proc->p_pid;
 
 	if (fuse_isdeadfs(vp)) {
 		return ENXIO;
@@ -1266,7 +1280,7 @@ fuse_vnop_read(struct vop_read_args *ap)
 		ioflag |= IO_DIRECT;
 	}
 
-	return fuse_io_dispatch(vp, uio, ioflag, cred);
+	return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
 }
 
 /*
@@ -1285,12 +1299,11 @@ fuse_vnop_readdir(struct vop_readdir_args *ap)
 	struct vnode *vp = ap->a_vp;
 	struct uio *uio = ap->a_uio;
 	struct ucred *cred = ap->a_cred;
-
 	struct fuse_filehandle *fufh = NULL;
 	struct fuse_iov cookediov;
-
 	int err = 0;
 	int freefufh = 0;
+	pid_t pid = curthread->td_proc->p_pid;
 
 	if (fuse_isdeadfs(vp)) {
 		return ENXIO;
@@ -1300,7 +1313,7 @@ fuse_vnop_readdir(struct vop_readdir_args *ap)
 		return EINVAL;
 	}
 
-	if ((err = fuse_filehandle_get(vp, FUFH_RDONLY, &fufh)) != 0) {
+	if ((err = fuse_filehandle_get_dir(vp, &fufh, cred, pid)) != 0) {
 		SDT_PROBE2(fuse, , vnops, trace, 1,
 			"calling readdir() before open()");
 		err = fuse_filehandle_open(vp, O_RDONLY, &fufh, NULL, cred);
@@ -1550,6 +1563,7 @@ fuse_vnop_setattr(struct vop_setattr_args *ap)
 	struct fuse_dispatcher fdi;
 	struct fuse_setattr_in *fsai;
 	struct fuse_access_param facp;
+	pid_t pid = td->td_proc->p_pid;
 
 	int err = 0;
 	enum vtype vtyp;
@@ -1589,7 +1603,7 @@ fuse_vnop_setattr(struct vop_setattr_args *ap)
 		newsize = vap->va_size;
 		fsai->valid |= FATTR_SIZE;
 
-		fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
+		fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh, cred, pid);
 		if (fufh) {
 			fsai->fh = fufh->fh_id;
 			fsai->valid |= FATTR_FH;
@@ -1760,6 +1774,7 @@ fuse_vnop_write(struct vop_write_args *ap)
 	struct uio *uio = ap->a_uio;
 	int ioflag = ap->a_ioflag;
 	struct ucred *cred = ap->a_cred;
+	pid_t pid = curthread->td_proc->p_pid;
 	int err;
 
 	if (fuse_isdeadfs(vp)) {
@@ -1773,7 +1788,7 @@ fuse_vnop_write(struct vop_write_args *ap)
 		ioflag |= IO_DIRECT;
 	}
 
-	return fuse_io_dispatch(vp, uio, ioflag, cred);
+	return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
 }
 
 SDT_PROBE_DEFINE1(fuse, , vnops, vnop_getpages_error, "int");
@@ -1797,6 +1812,7 @@ fuse_vnop_getpages(struct vop_getpages_args *ap)
 	struct thread *td;
 	struct ucred *cred;
 	vm_page_t *pages;
+	pid_t pid = curthread->td_proc->p_pid;
 
 	vp = ap->a_vp;
 	KASSERT(vp->v_object, ("objectless vp passed to getpages"));
@@ -1846,7 +1862,7 @@ fuse_vnop_getpages(struct vop_getpages_args *ap)
 	uio.uio_rw = UIO_READ;
 	uio.uio_td = td;
 
-	error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
+	error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred, pid);
 	pmap_qremove(kva, npages);
 
 	uma_zfree(fuse_pbuf_zone, bp);
@@ -1929,6 +1945,7 @@ fuse_vnop_putpages(struct vop_putpages_args *ap)
 	struct ucred *cred;
 	vm_page_t *pages;
 	vm_ooffset_t fsize;
+	pid_t pid = curthread->td_proc->p_pid;
 
 	vp = ap->a_vp;
 	KASSERT(vp->v_object, ("objectless vp passed to putpages"));
@@ -1978,7 +1995,7 @@ fuse_vnop_putpages(struct vop_putpages_args *ap)
 	uio.uio_rw = UIO_WRITE;
 	uio.uio_td = td;
 
-	error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
+	error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred, pid);
 
 	pmap_qremove(kva, npages);
 	uma_zfree(fuse_pbuf_zone, bp);

Modified: projects/fuse2/tests/sys/fs/fusefs/allow_other.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/allow_other.cc	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/tests/sys/fs/fusefs/allow_other.cc	Mon Apr  1 20:42:15 2019	(r345781)
@@ -99,8 +99,7 @@ TEST_F(AllowOther, allowed)
  * visible to root.  The second process is unprivileged and shouldn't be able
  * to open the file, but does thanks to the bug
  */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236844 */
-TEST_F(AllowOther, DISABLED_privilege_escalation)
+TEST_F(AllowOther, privilege_escalation)
 {
 	const static char FULLPATH[] = "mountpoint/some_file.txt";
 	const static char RELPATH[] = "some_file.txt";

Modified: projects/fuse2/tests/sys/fs/fusefs/open.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/open.cc	Mon Apr  1 20:03:53 2019	(r345780)
+++ projects/fuse2/tests/sys/fs/fusefs/open.cc	Mon Apr  1 20:42:15 2019	(r345781)
@@ -165,8 +165,7 @@ TEST_F(Open, fifo)
  * credentials open the same file, even if they use the same mode.  This is
  * necessary so that the daemon can validate each set of credentials.
  */
-/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236844 */
-TEST_F(Open, DISABLED_multiple_creds)
+TEST_F(Open, multiple_creds)
 {
 	const static char FULLPATH[] = "mountpoint/some_file.txt";
 	const static char RELPATH[] = "some_file.txt";



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