[PATCH] cachefiles: reject copen before OPEN delivery completes
From: Yudistira Putra
Date: Wed Jun 24 2026 - 16:14:00 EST
cachefiles_ondemand_daemon_read() creates an anonymous fd for
CACHEFILES_OP_OPEN before copying the OPEN message to userspace.
If copy_to_user() fails after a partial copy, userspace may already
have observed the OPEN message id. A racing copen can then complete
the OPEN request before the failed-read cleanup finishes. This allows
the OPEN waiter to observe success even though daemon-side OPEN message
delivery failed.
Record when the OPEN message has actually been delivered and the
anonymous fd has been installed. Reject copen before that point, so a
partially copied failed read cannot complete the OPEN request
successfully.
A local reproducer that faults the daemon read buffer previously showed
COPEN_FAST ok=1. With this change, the same reproducer reaches the
failed OPEN delivery path but copen is rejected consistently:
Trials: 10
READ EFAULT: 10
COPEN_FAST ok=0: 10
COPEN_FAST ok=1: 0
WATCHDOG_TIMEOUT: 0
Signed-off-by: Yudistira Putra <pyudistira519@xxxxxxxxx>
---
fs/cachefiles/internal.h | 1 +
fs/cachefiles/ondemand.c | 12 ++++++++++++
2 files changed, 13 insertions(+)
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
index b62cd3e..72fa413 100644
--- a/fs/cachefiles/internal.h
+++ b/fs/cachefiles/internal.h
@@ -143,6 +143,7 @@ struct cachefiles_req {
struct completion done;
refcount_t ref;
int error;
+ bool open_msg_delivered;
struct cachefiles_msg msg;
};
diff --git a/fs/cachefiles/ondemand.c b/fs/cachefiles/ondemand.c
index 0849eaf..16136ff 100644
--- a/fs/cachefiles/ondemand.c
+++ b/fs/cachefiles/ondemand.c
@@ -196,6 +196,17 @@ int cachefiles_ondemand_copen(struct cachefiles_cache *cache, char *args)
xa_unlock(&cache->reqs);
return -EINVAL;
}
+
+ /*
+ * The OPEN request must not be completed by copen until the
+ * daemon_read side has successfully delivered the OPEN message and
+ * installed the anonymous fd. Otherwise a daemon can use a partially
+ * copied message from a failed read to complete the request.
+ */
+ if (!READ_ONCE(req->open_msg_delivered)) {
+ xa_unlock(&cache->reqs);
+ return -EAGAIN;
+ }
xas_store(&xas, NULL);
xa_unlock(&cache->reqs);
@@ -469,6 +480,7 @@ ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
goto out;
}
fd_install(anon_file.fd, anon_file.file);
+ WRITE_ONCE(req->open_msg_delivered, true);
}
out:
cachefiles_put_object(req->object, cachefiles_obj_put_read_req);
--
2.43.0