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 v2 02/34] ecryptfs: fall back to a read-only lower file
Date: Thu, 29 Oct 2026 17:06:53 +0100 [thread overview]
Message-ID: <20261029-work-fs-sb_rdonly-v2-2-2f44f64f0b66@kernel.org> (raw)
In-Reply-To: <20261029-work-fs-sb_rdonly-v2-0-2f44f64f0b66@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), creating a file and opening an empty 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.
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/inode.c | 8 ++++++++
fs/ecryptfs/kthread.c | 15 +++++++++++++--
fs/ecryptfs/read_write.c | 3 +++
3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 3a966348a578..35afb94143b8 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 ae4cb4e2e134..d381d56baa90 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 b3b451c2b941..b3956ae50ff6 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
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
next prev parent reply other threads:[~2026-10-29 16:07 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 16:06 [PATCH v2 00/34] fs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-29 16:06 ` [PATCH v2 01/34] ecryptfs: don't leak the inode when a lookup can't open the lower file Christian Brauner
2026-10-29 16:06 ` Christian Brauner [this message]
2026-10-30 16:09 ` [PATCH v2 02/34] ecryptfs: fall back to a read-only " sashiko-bot
2026-10-29 16:06 ` [PATCH v2 03/34] fs: add a generic emergency read-only state Christian Brauner
2026-10-29 16:06 ` [PATCH v2 04/34] ext2: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-29 16:06 ` [PATCH v2 05/34] jfs: " Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 06/34] nilfs2: " Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 07/34] fat: " Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 08/34] exfat: keep the current mount options on remount Christian Brauner
2026-10-29 16:07 ` [PATCH v2 09/34] exfat: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 10/34] exfat: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 11/34] hfs: don't set SB_RDONLY after MDB write errors Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 12/34] hfs: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 13/34] hfsplus: don't set SB_RDONLY when creating the attributes tree Christian Brauner
2026-10-29 16:07 ` [PATCH v2 14/34] affs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-29 16:07 ` [PATCH v2 15/34] ufs: " Christian Brauner
2026-10-29 16:07 ` [PATCH v2 16/34] hpfs: " Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 17/34] ntfs: " Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 18/34] ntfs: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 19/34] ocfs2: keep the current mount options on remount Christian Brauner
2026-10-30 2:58 ` Joseph Qi
2026-10-29 16:07 ` [PATCH v2 20/34] ocfs2: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 3:01 ` Joseph Qi
2026-10-29 16:07 ` [PATCH v2 21/34] zonefs: don't set SB_RDONLY after I/O errors Christian Brauner
2026-10-29 16:07 ` [PATCH v2 22/34] zonefs: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 23/34] btrfs: check BTRFS_FS_STATE_RO instead of SB_RDONLY at runtime Christian Brauner
2026-10-29 16:07 ` [PATCH v2 24/34] btrfs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-29 16:07 ` [PATCH v2 25/34] gfs2: wait for a pending withdraw before remounting read-only Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 26/34] gfs2: don't set SB_RDONLY on withdraw Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 27/34] efivarfs: stop using SB_RDONLY for read-only efivar ops Christian Brauner
2026-10-29 16:07 ` [PATCH v2 28/34] ubifs: don't set SB_RDONLY after errors Christian Brauner
2026-10-30 3:42 ` Zhihao Cheng
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 29/34] selftests/filesystems: test filesystem errors while frozen Christian Brauner
2026-10-29 16:07 ` [PATCH v2 30/34] ext4: allow remounting read-only in the emergency state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 31/34] ext4: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 32/34] selftests/filesystems: test ext4 remounts in the emergency state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 33/34] xfs: allow remounting read-only after a shutdown Christian Brauner
2026-10-29 16:07 ` [PATCH v2 34/34] selftests/filesystems: test xfs remounts " 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=20261029-work-fs-sb_rdonly-v2-2-2f44f64f0b66@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