From: Christian Brauner <brauner@kernel.org>
To: linux-fsdevel@vger.kernel.org, Jan Kara <jack@suse.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>,
ecryptfs@vger.kernel.org, linux-ext4@vger.kernel.org,
jfs-discussion@lists.sourceforge.net,
linux-nilfs@vger.kernel.org, exfat@lists.linux.dev,
linux-mm@kvack.org, ntfs@lists.linux.dev,
ocfs2-devel@lists.linux.dev, linux-btrfs@vger.kernel.org,
gfs2@lists.linux.dev, linux-efi@vger.kernel.org,
linux-mtd@lists.infradead.org, linux-xfs@vger.kernel.org,
"Christian Brauner (Amutable)" <brauner@kernel.org>
Subject: [PATCH v3 04/33] ecryptfs: fall back to a read-only lower file
Date: Fri, 13 Nov 2026 12:59:00 +0100 [thread overview]
Message-ID: <20261113-work-fs-sb_rdonly-v3-4-0be92bb73709@kernel.org> (raw)
In-Reply-To: <20261113-work-fs-sb_rdonly-v3-0-0be92bb73709@kernel.org>
ecryptfs opens the lower file read-write unless the lower inode is
IS_RDONLY(). A read-only mount underneath refuses that and so does ext4
after an error since commit d3476f3dad4a ("ext4: don't set SB_RDONLY
after filesystem errors"). Then every lookup of a regular file fails
with EROFS. The other filesystems are about to behave like ext4, so fall
back to opening the lower file read-only. Opening an ecryptfs file for
writing then fails with EPERM like on top of a read-only superblock.
truncate(2) and creating a file still write to the lower file and
would trip the WARN_ON_ONCE() in __kernel_write_iter(). So let
ecryptfs_write_lower() and __ecryptfs_truncate() refuse that with EROFS.
Opening an empty file doesn't try to write the header through a
read-only lower file at all, read_or_initialize_metadata() skips it and
the open fails with EIO.
Note that ecryptfs never takes write access on the lower mount. On a
read-only bind mount that was only a problem for directories so far.
With this regular files can be unlinked and changed through it too.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
fs/ecryptfs/file.c | 4 +++-
fs/ecryptfs/inode.c | 8 ++++++++
fs/ecryptfs/kthread.c | 15 +++++++++++++--
fs/ecryptfs/read_write.c | 3 +++
4 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 49b0fbe0428a2..626de51e7dba5 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -170,8 +170,10 @@ static int read_or_initialize_metadata(struct dentry *dentry)
goto out;
}
+ /* The header can only be written through a writable lower file. */
if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) &&
- !i_size_read(ecryptfs_inode_to_lower(inode))) {
+ !i_size_read(ecryptfs_inode_to_lower(inode)) &&
+ (ecryptfs_inode_to_private(inode)->lower_file->f_mode & FMODE_WRITE)) {
rc = ecryptfs_initialize_file(dentry, inode);
if (!rc)
goto out;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 3a966348a578a..35afb94143b8a 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -741,6 +741,7 @@ static int __ecryptfs_truncate(struct dentry *dentry, const struct iattr *ia)
loff_t i_size = i_size_read(inode);
loff_t lower_size_before_truncate;
loff_t lower_size_after_truncate;
+ struct file *lower_file;
struct iattr lower_ia;
size_t num_zeros;
int rc;
@@ -771,6 +772,13 @@ static int __ecryptfs_truncate(struct dentry *dentry, const struct iattr *ia)
if (rc)
return rc;
+ /* Fail before zeroing the page cache, see ecryptfs_write_lower(). */
+ lower_file = ecryptfs_inode_to_private(inode)->lower_file;
+ if (!(lower_file->f_mode & FMODE_WRITE)) {
+ rc = -EROFS;
+ goto out;
+ }
+
if (ia->ia_size > i_size) {
char zero[] = { 0x00 };
diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
index ae4cb4e2e1348..d381d56baa90b 100644
--- a/fs/ecryptfs/kthread.c
+++ b/fs/ecryptfs/kthread.c
@@ -30,6 +30,17 @@ static struct ecryptfs_kthread_ctl {
static struct task_struct *ecryptfs_kthread;
+/* A read-only mount or a filesystem that hit an error refuses O_RDWR. */
+static struct file *ecryptfs_open_lower(const struct path *path, int flags,
+ const struct cred *cred)
+{
+ struct file *file = dentry_open(path, flags, cred);
+
+ if (PTR_ERR_OR_ZERO(file) == -EROFS && (flags & O_ACCMODE) == O_RDWR)
+ file = dentry_open(path, (flags & ~O_ACCMODE) | O_RDONLY, cred);
+ return file;
+}
+
/**
* ecryptfs_threadfn
* @ignored: ignored
@@ -59,7 +70,7 @@ static int ecryptfs_threadfn(void *ignored)
struct ecryptfs_open_req,
kthread_ctl_list);
list_del(&req->kthread_ctl_list);
- *req->lower_file = dentry_open(&req->path,
+ *req->lower_file = ecryptfs_open_lower(&req->path,
(O_RDWR | O_LARGEFILE), current_cred());
complete(&req->done);
}
@@ -132,7 +143,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
* lower file is fput() when all eCryptfs files for the inode are
* released. */
flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR;
- (*lower_file) = dentry_open(&req.path, flags, cred);
+ (*lower_file) = ecryptfs_open_lower(&req.path, flags, cred);
if (!IS_ERR(*lower_file))
goto out;
if ((flags & O_ACCMODE) == O_RDONLY) {
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index b3b451c2b9410..b3956ae50ff66 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -33,6 +33,9 @@ int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
if (!lower_file)
return -EIO;
+ /* ecryptfs_open_lower() may have fallen back to a read-only file. */
+ if (!(lower_file->f_mode & FMODE_WRITE))
+ return -EROFS;
rc = kernel_write(lower_file, data, size, &offset);
mark_inode_dirty_sync(ecryptfs_inode);
return rc;
--
2.53.0
next prev parent reply other threads:[~2026-11-13 12:00 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 11:58 [PATCH v3 00/33] fs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-11-13 11:58 ` [PATCH v3 01/33] jfs: free uncommitted anonymous tlocks when evicting an inode Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:58 ` [PATCH v3 02/33] jfs: use jfs_symlink_inode_operations in jfs_iget() Christian Brauner
2026-11-13 11:58 ` [PATCH v3 03/33] ecryptfs: don't leak the inode when a lookup can't open the lower file Christian Brauner
2026-11-13 11:59 ` Christian Brauner [this message]
2026-11-13 11:59 ` [PATCH v3 05/33] fs: add a generic emergency read-only state Christian Brauner
2026-11-13 14:53 ` Jan Kara
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 06/33] ext2: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-11-13 14:54 ` Jan Kara
2026-11-13 11:59 ` [PATCH v3 07/33] jfs: " Christian Brauner
2026-11-13 11:59 ` [PATCH v3 08/33] nilfs2: " Christian Brauner
2026-11-13 11:59 ` [PATCH v3 09/33] fat: " Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 10/33] exfat: keep the current mount options on remount Christian Brauner
2026-11-13 11:59 ` [PATCH v3 11/33] exfat: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 12/33] exfat: use the generic emergency read-only state Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 13/33] hfs: don't set SB_RDONLY after MDB write errors Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 14/33] hfs: use the generic emergency read-only state Christian Brauner
2026-11-13 11:59 ` [PATCH v3 15/33] hfsplus: don't set SB_RDONLY when creating the attributes tree Christian Brauner
2026-11-13 11:59 ` [PATCH v3 16/33] affs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-11-13 11:59 ` [PATCH v3 17/33] ufs: " Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 18/33] hpfs: " Christian Brauner
2026-11-13 11:59 ` [PATCH v3 19/33] ntfs: " Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 20/33] ntfs: use the generic emergency read-only state Christian Brauner
2026-11-13 11:59 ` [PATCH v3 21/33] ocfs2: keep the current mount options on remount Christian Brauner
2026-11-13 11:59 ` [PATCH v3 22/33] ocfs2: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-11-13 11:59 ` [PATCH v3 23/33] zonefs: don't set SB_RDONLY after I/O errors Christian Brauner
2026-11-13 11:59 ` [PATCH v3 24/33] zonefs: use the generic emergency read-only state Christian Brauner
2026-11-13 11:59 ` [PATCH v3 25/33] btrfs: check BTRFS_FS_STATE_RO instead of SB_RDONLY at runtime Christian Brauner
2026-11-13 11:59 ` [PATCH v3 26/33] btrfs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 27/33] gfs2: wait for a pending withdraw before remounting read-only Christian Brauner
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 28/33] gfs2: don't set SB_RDONLY on withdraw Christian Brauner
2026-11-13 11:59 ` [PATCH v3 29/33] efivarfs: stop using SB_RDONLY for read-only efivar ops Christian Brauner
2026-11-13 11:59 ` [PATCH v3 30/33] ubifs: don't set SB_RDONLY after errors Christian Brauner
2026-11-14 2:17 ` Zhihao Cheng
2026-11-14 12:03 ` sashiko-bot
2026-11-13 11:59 ` [PATCH v3 31/33] ext4: allow remounting read-only in the emergency state Christian Brauner
2026-11-13 11:59 ` [PATCH v3 32/33] ext4: use the generic emergency read-only state Christian Brauner
2026-11-13 11:59 ` [PATCH v3 33/33] xfs: allow remounting read-only after a shutdown Christian Brauner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261113-work-fs-sb_rdonly-v3-4-0be92bb73709@kernel.org \
--to=brauner@kernel.org \
--cc=ecryptfs@vger.kernel.org \
--cc=exfat@lists.linux.dev \
--cc=gfs2@lists.linux.dev \
--cc=jack@suse.com \
--cc=jfs-discussion@lists.sourceforge.net \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-mtd@lists.infradead.org \
--cc=linux-nilfs@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=ntfs@lists.linux.dev \
--cc=ocfs2-devel@lists.linux.dev \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox