Forbid truncate of fsverity files on btrfs
Subsystems (5)
Eric Biggers
maintainercover Forbid truncate of fsverity files on btrfs
Backport the fix to forbid truncate(2) of fsverity files on btrfs (and also the fix for that fix).
Andrey Albershteyn (1):
fs,fsverity: remove check for fsverity being enabled in
setattr_prepare()
Christoph Hellwig (1):
fs,fsverity: reject size changes on fsverity files in setattr_prepare
fs/attr.c | 12 +++++++++++- fs/ext4/inode.c | 4 ---- fs/f2fs/file.c | 4 ---- fs/verity/open.c | 8 -------- include/linux/fsverity.h | 25 ------------------------- 5 files changed, 11 insertions(+), 42 deletions(-)
base-commit: 725bd2f3c81d54edccb66fead01d4c0c222e2231
Signature · 1 line
2.56.0
Eric Biggers
maintainerPATCH 1/2 fs,fsverity: reject size changes on fsverity files in setattr_prepare
From: Christoph Hellwig <[email protected]>
commit e9734653c523c744f03333ece6ae7a315187f05c upstream.
Add the check to reject truncates of fsverity files directly to setattr_prepare instead of requiring the file system to handle it. Besides removing boilerplate code, this also fixes the complete lack of such check in btrfs.
--- fs/attr.c | 12 +++++++++++- fs/ext4/inode.c | 4 ---- fs/f2fs/file.c | 4 ---- fs/verity/open.c | 8 -------- include/linux/fsverity.h | 25 ------------------------- 5 files changed, 11 insertions(+), 42 deletions(-)
fs/attr.c +11 -1
@@ -169,7 +169,17 @@ int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry,* ATTR_FORCE. */ if (ia_valid &ATTR_SIZE ) { -int error =inode_newsize_ok (inode, attr->ia_size); +int error; + +/* +* Verity files are immutable, so deny truncates. This isn't +* covered by the open-time check because sys_truncate() takes a +* path, not an open file. +*/ +if (IS_ENABLED (CONFIG_FS_VERITY ) &&IS_VERITY (inode)) +return -EPERM ; + + error =inode_newsize_ok (inode, attr->ia_size);if (error)return error; }
fs/ext4/inode.c +0 -4
@@ -5898,10 +5898,6 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,if (error)return error; - error =fsverity_prepare_setattr (dentry, attr); -if (error) -return error; -if (is_quota_modification (idmap, inode, attr)) { error =dquot_initialize (inode);if (error)
fs/f2fs/file.c +0 -4
@@ -1123,10 +1123,6 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,if (err)return err; - err =fsverity_prepare_setattr (dentry, attr); -if (err) -return err; -if (unlikely (IS_IMMUTABLE (inode)))return -EPERM ;
fs/verity/open.c +0 -8
@@ -384,14 +384,6 @@ int __fsverity_file_open(struct inode *inode, struct file *filp) }EXPORT_SYMBOL_GPL (__fsverity_file_open); -int __fsverity_prepare_setattr (struct dentry *dentry,struct iattr *attr) -{ -if (attr->ia_valid &ATTR_SIZE ) -return -EPERM ; -return 0 ; -} -EXPORT_SYMBOL_GPL (__fsverity_prepare_setattr); -void __fsverity_cleanup_inode (struct inode *inode) {struct fsverity_info **vi_addr =fsverity_info_addr (inode);
include/linux/fsverity.h +0 -25
@@ -179,7 +179,6 @@ int fsverity_get_digest(struct inode *inode,/* open.c */ int __fsverity_file_open (struct inode *inode,struct file *filp); -int __fsverity_prepare_setattr (struct dentry *dentry,struct iattr *attr);void __fsverity_cleanup_inode (struct inode *inode);/**
@@ -251,12 +250,6 @@ static inline int __fsverity_file_open(struct inode *inode, struct file *filp)return -EOPNOTSUPP ; } -static inline int __fsverity_prepare_setattr (struct dentry *dentry, -struct iattr *attr) -{ -return -EOPNOTSUPP ; -} -static inline void fsverity_cleanup_inode (struct inode *inode) { }
@@ -338,22 +331,4 @@ static inline int fsverity_file_open(struct inode *inode, struct file *filp) return 0; } -/** -* fsverity_prepare_setattr() - prepare to change a verity inode's attributes -* @dentry: dentry through which the inode is being changed -* @attr: attributes to change -* -* Verity files are immutable, so deny truncates. This isn't covered by the -* open-time check because sys_truncate() takes a path, not a file descriptor. -* -* Return: 0 on success, -errno on failure -*/ -static inline int fsverity_prepare_setattr (struct dentry *dentry, -struct iattr *attr) -{ -if (IS_VERITY (d_inode (dentry))) -return __fsverity_prepare_setattr (dentry, attr); -return 0 ; -} -#endif /* _LINUX_FSVERITY_H */
Signature · 1 line
2.56.0
Patch "fs,fsverity: reject size changes on fsverity files in setattr_prepare" has been added to the 6.18-stable tree
This is a note to let you know that I've just added the patch titled
fs,fsverity: reject size changes on fsverity files in setattr_prepare
to the 6.18-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
fs-fsverity-reject-size-changes-on-fsverity-files-in-setattr_prepare.patch
and it can be found in the queue-6.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
From [email protected] Tue Oct 6 23:38:38 2026
From: Eric Biggers <[email protected]>
Date: Tue, 6 Oct 2026 23:36:04 +0200
Subject: fs,fsverity: reject size changes on fsverity files in setattr_prepare
To: [email protected]
Cc: [email protected], Christoph Hellwig <[email protected]>, Jan Kara <[email protected]>, "Darrick J. Wong" <[email protected]>, Eric Biggers <[email protected]>
Message-ID: <[email protected]>
From: Christoph Hellwig <[email protected]>
commit e9734653c523c744f03333ece6ae7a315187f05c upstream.
Add the check to reject truncates of fsverity files directly to setattr_prepare instead of requiring the file system to handle it. Besides removing boilerplate code, this also fixes the complete lack of such check in btrfs.
--- fs/attr.c | 12 +++++++++++- fs/ext4/inode.c | 4 ---- fs/f2fs/file.c | 4 ---- fs/verity/open.c | 8 -------- include/linux/fsverity.h | 25 ------------------------- 5 files changed, 11 insertions(+), 42 deletions(-)
fs/attr.c +11 -1
@@ -169,7 +169,17 @@ int setattr_prepare(struct mnt_idmap *id* ATTR_FORCE. */ if (ia_valid &ATTR_SIZE ) { -int error =inode_newsize_ok (inode, attr->ia_size); +int error; + +/* +* Verity files are immutable, so deny truncates. This isn't +* covered by the open-time check because sys_truncate() takes a +* path, not an open file. +*/ +if (IS_ENABLED (CONFIG_FS_VERITY ) &&IS_VERITY (inode)) +return -EPERM ; + + error =inode_newsize_ok (inode, attr->ia_size);if (error)return error; }
fs/ext4/inode.c +0 -4
@@ -5898,10 +5898,6 @@ int ext4_setattr(struct mnt_idmap *idmapif (error)return error; - error =fsverity_prepare_setattr (dentry, attr); -if (error) -return error; -if (is_quota_modification (idmap, inode, attr)) { error =dquot_initialize (inode);if (error)
fs/f2fs/file.c +0 -4
@@ -1123,10 +1123,6 @@ int f2fs_setattr(struct mnt_idmap *idmapif (err)return err; - err =fsverity_prepare_setattr (dentry, attr); -if (err) -return err; -if (unlikely (IS_IMMUTABLE (inode)))return -EPERM ;
fs/verity/open.c +0 -8
@@ -384,14 +384,6 @@ int __fsverity_file_open(struct inode *i }EXPORT_SYMBOL_GPL (__fsverity_file_open); -int __fsverity_prepare_setattr (struct dentry *dentry,struct iattr *attr) -{ -if (attr->ia_valid &ATTR_SIZE ) -return -EPERM ; -return 0 ; -} -EXPORT_SYMBOL_GPL (__fsverity_prepare_setattr); -void __fsverity_cleanup_inode (struct inode *inode) {struct fsverity_info **vi_addr =fsverity_info_addr (inode);
include/linux/fsverity.h +0 -25
@@ -179,7 +179,6 @@ int fsverity_get_digest(struct inode *in/* open.c */ int __fsverity_file_open (struct inode *inode,struct file *filp); -int __fsverity_prepare_setattr (struct dentry *dentry,struct iattr *attr);void __fsverity_cleanup_inode (struct inode *inode);/**
@@ -251,12 +250,6 @@ static inline int __fsverity_file_open(sreturn -EOPNOTSUPP ; } -static inline int __fsverity_prepare_setattr (struct dentry *dentry, -struct iattr *attr) -{ -return -EOPNOTSUPP ; -} -static inline void fsverity_cleanup_inode (struct inode *inode) { }
@@ -338,22 +331,4 @@ static inline int fsverity_file_open(str return 0; } -/** -* fsverity_prepare_setattr() - prepare to change a verity inode's attributes -* @dentry: dentry through which the inode is being changed -* @attr: attributes to change -* -* Verity files are immutable, so deny truncates. This isn't covered by the -* open-time check because sys_truncate() takes a path, not a file descriptor. -* -* Return: 0 on success, -errno on failure -*/ -static inline int fsverity_prepare_setattr (struct dentry *dentry, -struct iattr *attr) -{ -if (IS_VERITY (d_inode (dentry))) -return __fsverity_prepare_setattr (dentry, attr); -return 0 ; -} -#endif /* _LINUX_FSVERITY_H */
Patches currently in stable-queue which might be from [email protected] are
queue-6.18/fs-fsverity-reject-size-changes-on-fsverity-files-in-setattr_prepare.patch queue-6.18/fs-fsverity-remove-check-for-fsverity-being-enabled-in-setattr_prepare.patch queue-6.18/fsverity-add-dependency-on-64k-or-smaller-pages.patch queue-6.18/crypto-x86-aes-gcm-fix-always-true-check-for-last-aad-segment.patch
[email protected]
AI reviewRe: Patch "fs,fsverity: reject size changes on fsverity files in setattr_prepare" has been added to the 6.18-stable tree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] vfs: verity file truncation bypass when CONFIG_FS_VERITY is disabled --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] vfs: verity file truncation bypass when CONFIG_FS_VERITY is disabled --
commit 750dd8cb058f7ea5d2ca5305006f1c5e63c6eb32
Author: [email protected] <[email protected]>
fs,fsverity: reject size changes on fsverity files in setattr_prepare
This commit centralizes the check to reject truncates of fsverity files into setattr_prepare() in fs/attr.c. This removes boilerplate code from individual filesystems and fixes a missing truncation check in btrfs.
Quoted 8 lines
fs/attr.c +0
-0@@ -169,7 +169,17 @@ int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry,* ATTR_FORCE. */ if (ia_valid &ATTR_SIZE ) {
fs/attr.c int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry, · line 180
Quoted 10 lines
fs/attr.c +9
-1-int error =inode_newsize_ok (inode, attr->ia_size); +int error; + +/* +* Verity files are immutable, so deny truncates. This isn't +* covered by the open-time check because sys_truncate() takes a +* path, not an open file. +*/ +if (IS_ENABLED (CONFIG_FS_VERITY ) &&IS_VERITY (inode)) +return -EPERM ;
[Severity: High]
Does this logic inadvertently permit truncating verity files when CONFIG_FS_VERITY is disabled?
Before this patch, filesystems explicitly called fsverity_prepare_setattr(). When CONFIG_FS_VERITY was disabled, the fallback implementation safely returned -EOPNOTSUPP for any inode with the verity flag set.
By short-circuiting the check here with IS_ENABLED(CONFIG_FS_VERITY), it appears an unprivileged user with DAC write access could use sys_truncate() to bypass the check and modify a verity file if the kernel was built without fsverity support.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/2026100754-drizzle-shape-0a72@gregkh?part=1
Eric Biggers
maintainerPATCH 2/2 fs,fsverity: remove check for fsverity being enabled in setattr_prepare()
In reply to Eric BiggersFrom: Andrey Albershteyn <[email protected]>
commit d2f96bcb89d36d488a10e3bcf819b98536968286 upstream.
The check that fs-verity is available in the kernel is not necessary here. Filesystems could have fsverity files even without fs-verity enabled. In that case, truncate on fsverity file will succeed, what this check is trying to prevent.
--- fs/attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/attr.c +1 -1
@@ -176,7 +176,7 @@ int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry,* covered by the open-time check because sys_truncate() takes a * path, not an open file. */ -if (IS_ENABLED (CONFIG_FS_VERITY ) &&IS_VERITY (inode)) +if (IS_VERITY (inode))return -EPERM ; error =inode_newsize_ok (inode, attr->ia_size);
Signature · 1 line
2.56.0
Patch "fs,fsverity: remove check for fsverity being enabled in setattr_prepare()" has been added to the 6.18-stable tree
This is a note to let you know that I've just added the patch titled
fs,fsverity: remove check for fsverity being enabled in setattr_prepare()
to the 6.18-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
fs-fsverity-remove-check-for-fsverity-being-enabled-in-setattr_prepare.patch
and it can be found in the queue-6.18 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
From [email protected] Tue Oct 6 23:39:37 2026
From: Eric Biggers <[email protected]>
Date: Tue, 6 Oct 2026 23:36:05 +0200
Subject: fs,fsverity: remove check for fsverity being enabled in setattr_prepare()
To: [email protected]
Cc: [email protected], Andrey Albershteyn <[email protected]>, Christoph Hellwig <[email protected]>, Eric Biggers <[email protected]>
Message-ID: <[email protected]>
From: Andrey Albershteyn <[email protected]>
commit d2f96bcb89d36d488a10e3bcf819b98536968286 upstream.
The check that fs-verity is available in the kernel is not necessary here. Filesystems could have fsverity files even without fs-verity enabled. In that case, truncate on fsverity file will succeed, what this check is trying to prevent.
--- fs/attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/attr.c +1 -1
@@ -176,7 +176,7 @@ int setattr_prepare(struct mnt_idmap *id* covered by the open-time check because sys_truncate() takes a * path, not an open file. */ -if (IS_ENABLED (CONFIG_FS_VERITY ) &&IS_VERITY (inode)) +if (IS_VERITY (inode))return -EPERM ; error =inode_newsize_ok (inode, attr->ia_size);
Patches currently in stable-queue which might be from [email protected] are
queue-6.18/fs-fsverity-reject-size-changes-on-fsverity-files-in-setattr_prepare.patch queue-6.18/fs-fsverity-remove-check-for-fsverity-being-enabled-in-setattr_prepare.patch queue-6.18/fsverity-add-dependency-on-64k-or-smaller-pages.patch queue-6.18/crypto-x86-aes-gcm-fix-always-true-check-for-last-aad-segment.patch