aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Richardson <arichardson@FreeBSD.org>2026-05-07 04:23:27 +0000
committerAlex Richardson <arichardson@FreeBSD.org>2026-05-07 04:23:28 +0000
commit40d59ee35dc106cda88d66e37527975a32596cd7 (patch)
tree708510571311b73bf0d0af6cdd4089e5df09d0aa
parent96b2f4a9124158f27c4c27c32f6fa1a6018250fb (diff)
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
-rw-r--r--sys/fs/p9fs/p9fs_subr.c14
-rw-r--r--sys/fs/p9fs/p9fs_vnops.c24
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;