The branch main has been updated by arichardson:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=40d59ee35dc106cda88d66e37527975a32596cd7

commit 40d59ee35dc106cda88d66e37527975a32596cd7
Author:     Alex Richardson <[email protected]>
AuthorDate: 2026-05-07 04:23:27 +0000
Commit:     Alex Richardson <[email protected]>
CommitDate: 2026-05-07 04:23:28 +0000

    p9fs: Fix creating files with restrictive permissions
    
    When a file is created via p9fs with restrictive permissions (like 000),
    the 9P TCREATE request successfully creates and natively opens the file,
    returning an open, writable file descriptor. Previously, p9fs would
    attempt a subsequent TOPEN. That TOPEN would fail with EACCES due to the
    restrictive mode, leaving a 0-byte file and causing operations like 'mv'
    to abort.
    
    We now preserve the writable descriptor returned by TCREATE so that the
    subsequent VOP_OPEN can use it directly, avoiding the failing TOPEN.
    Additionally, p9fs_compatible_mode now appropriately isolates the base
    access intent when matching fids, preventing extended flags from
    breaking the match.
    
    A test case for this behavior has been submitted to pjdfstest:
    https://github.com/pjd/pjdfstest/pull/87
    
    Resolves: https://github.com/CTSRD-CHERI/cheribsd/issues/2617
    
    Reviewed by:    markj
    MFC after:      1 week
    Differential Revision: https://reviews.freebsd.org/D56494
---
 sys/fs/p9fs/p9fs_subr.c  | 14 +++++++++-----
 sys/fs/p9fs/p9fs_vnops.c | 24 +++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/sys/fs/p9fs/p9fs_subr.c b/sys/fs/p9fs/p9fs_subr.c
index d0f04f6c5e97..f66e7a171029 100644
--- a/sys/fs/p9fs/p9fs_subr.c
+++ b/sys/fs/p9fs/p9fs_subr.c
@@ -275,16 +275,20 @@ p9fs_compatible_mode(struct p9_fid *fid, int mode)
 {
        /*
         * Return TRUE for an exact match. For OREAD and OWRITE, allow
-        * existing ORDWR fids to match. Only check the low two bits
-        * of mode.
+        * existing ORDWR fids to match.
         *
-        * TODO: figure out if this is correct for O_APPEND
+        * We mask both the requested mode and the existing fid's mode
+        * with 3 (0b11) to isolate the base access intent (O_RDONLY,
+        * O_WRONLY, or O_RDWR). This prevents extended open flags like
+        * O_EXCL or O_APPEND from causing a mismatch when we are merely
+        * looking for an appropriately privileged open descriptor.
         */
        int fid_mode = fid->mode & 3;
-       if (fid_mode == mode)
+       int req_mode = mode & 3;
+       if (fid_mode == req_mode)
                return (TRUE);
        if (fid_mode == P9PROTO_ORDWR)
-               return (mode == P9PROTO_OREAD || mode == P9PROTO_OWRITE);
+               return (req_mode == P9PROTO_OREAD || req_mode == 
P9PROTO_OWRITE);
        return (FALSE);
 }
 
diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c
index ad739a219acb..2519e5cd050a 100644
--- a/sys/fs/p9fs/p9fs_vnops.c
+++ b/sys/fs/p9fs/p9fs_vnops.c
@@ -419,7 +419,7 @@ out:
  * the name and perm specified under the parent dir. If this succeeds (an entry
  * is created for the new file on the server), we create our metadata for this
  * file (vnode, p9fs node calling vget). Once we are done, we clunk the open
- * fid of the parent directory.
+ * fid of the parent directory if it was not retained.
  */
 static int
 create_common(struct p9fs_node *dnp, struct componentname *cnp,
@@ -473,6 +473,28 @@ create_common(struct p9fs_node *dnp, struct componentname 
*cnp,
                            dnp, newfid, vpp, cnp->cn_nameptr);
                        if (error != 0)
                                goto out;
+
+                       if (ofid != NULL) {
+                               struct p9fs_node *np = P9FS_VTON(*vpp);
+                               ofid->v_opens = 0;
+                               /*
+                                * The 9P file creation request natively opens
+                                * the file as part of the create operation and
+                                * gives us a writable file handle (ofid).
+                                * We retain this open descriptor by adding it
+                                * to the VOFID list of the new vnode. This
+                                * guarantees that a subsequent VOP_OPEN call
+                                * does not need to send a redundant TOPEN
+                                * request. This is particularly important
+                                * because if a file was requested to be created
+                                * with 000 permissions, the host will reject
+                                * subsequent TOPEN requests due to insufficient
+                                * permissions, which would cause an overall
+                                * open() failure.
+                                */
+                               p9fs_fid_add(np, ofid, VOFID);
+                               ofid = NULL; /* prevent closing handle below */
+                       }
                } else {
                        /* Not found return NOENTRY.*/
                        goto out;

Reply via email to