* [PATCH 0/2] efivarfs: fix ability to mimic uncommitted variables @ 2025-01-19 14:59 James Bottomley 2025-01-19 14:59 ` [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache James Bottomley 2025-01-19 14:59 ` [PATCH 2/2] selftests/efivarfs: add check for disallowing file truncation James Bottomley 0 siblings, 2 replies; 6+ messages in thread From: James Bottomley @ 2025-01-19 14:59 UTC (permalink / raw) To: linux-fsdevel, linux-efi Cc: Ard Biesheuvel, Jeremy Kerr, Christian Brauner, Al Viro The use of simple_setattr in efivarfs means that anyone who can write to the variable (which is usually only root) can set the cached inode size to an arbitrary value (including truncating it to zero). This value, while not transmitted on to the underlying variable, does show up on stat and means that anyone who can write to the variable file can also make any variable mimic an uncommitted one (a variable with zero size) which is checked by certain programmes that use EFI variables, like systemd. This problem can be fixed by not allowing anything except a successful variable update to change the inode size. I also added a regression test to make sure the problem behaviour isn't reintroduced. James --- James Bottomley (2): efivarfs: prevent setting of zero size on the inodes in the cache selftests/efivarfs: add check for disallowing file truncation fs/efivarfs/inode.c | 17 +++++++++++++++ tools/testing/selftests/efivarfs/efivarfs.sh | 23 ++++++++++++++++++++ 2 files changed, 40 insertions(+) -- 2.35.3 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache 2025-01-19 14:59 [PATCH 0/2] efivarfs: fix ability to mimic uncommitted variables James Bottomley @ 2025-01-19 14:59 ` James Bottomley 2025-01-19 16:32 ` Ard Biesheuvel 2025-01-19 14:59 ` [PATCH 2/2] selftests/efivarfs: add check for disallowing file truncation James Bottomley 1 sibling, 1 reply; 6+ messages in thread From: James Bottomley @ 2025-01-19 14:59 UTC (permalink / raw) To: linux-fsdevel, linux-efi Cc: Ard Biesheuvel, Jeremy Kerr, Christian Brauner, Al Viro Current efivarfs uses simple_setattr which allows the setting of any size in the inode cache. This is wrong because a zero size file is used to indicate an "uncommitted" variable, so by simple means of truncating the file (as root) any variable may be turned to look like it's uncommitted. Fix by adding an efivarfs_setattr routine which does not allow updating of the cached inode size (which now only comes from the underlying variable). Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> --- fs/efivarfs/inode.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index ec23da8405ff..a4a6587ecd2e 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -187,7 +187,24 @@ efivarfs_fileattr_set(struct mnt_idmap *idmap, return 0; } +/* copy of simple_setattr except that it doesn't do i_size updates */ +static int efivarfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + struct iattr *iattr) +{ + struct inode *inode = d_inode(dentry); + int error; + + error = setattr_prepare(idmap, dentry, iattr); + if (error) + return error; + + setattr_copy(idmap, inode, iattr); + mark_inode_dirty(inode); + return 0; +} + static const struct inode_operations efivarfs_file_inode_operations = { .fileattr_get = efivarfs_fileattr_get, .fileattr_set = efivarfs_fileattr_set, + .setattr = efivarfs_setattr, }; -- 2.35.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache 2025-01-19 14:59 ` [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache James Bottomley @ 2025-01-19 16:32 ` Ard Biesheuvel 2025-01-19 16:48 ` James Bottomley 0 siblings, 1 reply; 6+ messages in thread From: Ard Biesheuvel @ 2025-01-19 16:32 UTC (permalink / raw) To: James Bottomley Cc: linux-fsdevel, linux-efi, Jeremy Kerr, Christian Brauner, Al Viro On Sun, 19 Jan 2025 at 16:00, James Bottomley <James.Bottomley@hansenpartnership.com> wrote: > > Current efivarfs uses simple_setattr which allows the setting of any > size in the inode cache. This is wrong because a zero size file is > used to indicate an "uncommitted" variable, so by simple means of > truncating the file (as root) any variable may be turned to look like > it's uncommitted. Fix by adding an efivarfs_setattr routine which > does not allow updating of the cached inode size (which now only comes > from the underlying variable). > > Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> > --- > fs/efivarfs/inode.c | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > > diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c > index ec23da8405ff..a4a6587ecd2e 100644 > --- a/fs/efivarfs/inode.c > +++ b/fs/efivarfs/inode.c > @@ -187,7 +187,24 @@ efivarfs_fileattr_set(struct mnt_idmap *idmap, > return 0; > } > > +/* copy of simple_setattr except that it doesn't do i_size updates */ > +static int efivarfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, > + struct iattr *iattr) > +{ > + struct inode *inode = d_inode(dentry); > + int error; > + > + error = setattr_prepare(idmap, dentry, iattr); > + if (error) > + return error; > + > + setattr_copy(idmap, inode, iattr); > + mark_inode_dirty(inode); > + return 0; > +} > + > static const struct inode_operations efivarfs_file_inode_operations = { > .fileattr_get = efivarfs_fileattr_get, > .fileattr_set = efivarfs_fileattr_set, > + .setattr = efivarfs_setattr, > }; Is it sufficient to just ignore inode size changes? Should we complain about this instead? ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache 2025-01-19 16:32 ` Ard Biesheuvel @ 2025-01-19 16:48 ` James Bottomley 2025-01-19 16:52 ` Ard Biesheuvel 0 siblings, 1 reply; 6+ messages in thread From: James Bottomley @ 2025-01-19 16:48 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-fsdevel, linux-efi, Jeremy Kerr, Christian Brauner, Al Viro On Sun, 2025-01-19 at 17:32 +0100, Ard Biesheuvel wrote: > On Sun, 19 Jan 2025 at 16:00, James Bottomley > <James.Bottomley@hansenpartnership.com> wrote: > > > > Current efivarfs uses simple_setattr which allows the setting of > > any > > size in the inode cache. This is wrong because a zero size file is > > used to indicate an "uncommitted" variable, so by simple means of > > truncating the file (as root) any variable may be turned to look > > like > > it's uncommitted. Fix by adding an efivarfs_setattr routine which > > does not allow updating of the cached inode size (which now only > > comes > > from the underlying variable). > > > > Signed-off-by: James Bottomley > > <James.Bottomley@HansenPartnership.com> > > --- > > fs/efivarfs/inode.c | 17 +++++++++++++++++ > > 1 file changed, 17 insertions(+) > > > > diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c > > index ec23da8405ff..a4a6587ecd2e 100644 > > --- a/fs/efivarfs/inode.c > > +++ b/fs/efivarfs/inode.c > > @@ -187,7 +187,24 @@ efivarfs_fileattr_set(struct mnt_idmap *idmap, > > return 0; > > } > > > > +/* copy of simple_setattr except that it doesn't do i_size updates > > */ > > +static int efivarfs_setattr(struct mnt_idmap *idmap, struct dentry > > *dentry, > > + struct iattr *iattr) > > +{ > > + struct inode *inode = d_inode(dentry); > > + int error; > > + > > + error = setattr_prepare(idmap, dentry, iattr); > > + if (error) > > + return error; > > + > > + setattr_copy(idmap, inode, iattr); > > + mark_inode_dirty(inode); > > + return 0; > > +} > > + > > static const struct inode_operations > > efivarfs_file_inode_operations = { > > .fileattr_get = efivarfs_fileattr_get, > > .fileattr_set = efivarfs_fileattr_set, > > + .setattr = efivarfs_setattr, > > }; > > Is it sufficient to just ignore inode size changes? Yes, as far as my testing goes. > Should we complain about this instead? I don't think so because every variable write (at least from the shell) tends to start off with a truncation so we'd get a lot of spurious complaints. Regards, James ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache 2025-01-19 16:48 ` James Bottomley @ 2025-01-19 16:52 ` Ard Biesheuvel 0 siblings, 0 replies; 6+ messages in thread From: Ard Biesheuvel @ 2025-01-19 16:52 UTC (permalink / raw) To: James Bottomley Cc: linux-fsdevel, linux-efi, Jeremy Kerr, Christian Brauner, Al Viro On Sun, 19 Jan 2025 at 17:48, James Bottomley <James.Bottomley@hansenpartnership.com> wrote: > > On Sun, 2025-01-19 at 17:32 +0100, Ard Biesheuvel wrote: > > On Sun, 19 Jan 2025 at 16:00, James Bottomley > > <James.Bottomley@hansenpartnership.com> wrote: > > > > > > Current efivarfs uses simple_setattr which allows the setting of > > > any > > > size in the inode cache. This is wrong because a zero size file is > > > used to indicate an "uncommitted" variable, so by simple means of > > > truncating the file (as root) any variable may be turned to look > > > like > > > it's uncommitted. Fix by adding an efivarfs_setattr routine which > > > does not allow updating of the cached inode size (which now only > > > comes > > > from the underlying variable). > > > > > > Signed-off-by: James Bottomley > > > <James.Bottomley@HansenPartnership.com> > > > --- > > > fs/efivarfs/inode.c | 17 +++++++++++++++++ > > > 1 file changed, 17 insertions(+) > > > > > > diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c > > > index ec23da8405ff..a4a6587ecd2e 100644 > > > --- a/fs/efivarfs/inode.c > > > +++ b/fs/efivarfs/inode.c > > > @@ -187,7 +187,24 @@ efivarfs_fileattr_set(struct mnt_idmap *idmap, > > > return 0; > > > } > > > > > > +/* copy of simple_setattr except that it doesn't do i_size updates > > > */ > > > +static int efivarfs_setattr(struct mnt_idmap *idmap, struct dentry > > > *dentry, > > > + struct iattr *iattr) > > > +{ > > > + struct inode *inode = d_inode(dentry); > > > + int error; > > > + > > > + error = setattr_prepare(idmap, dentry, iattr); > > > + if (error) > > > + return error; > > > + > > > + setattr_copy(idmap, inode, iattr); > > > + mark_inode_dirty(inode); > > > + return 0; > > > +} > > > + > > > static const struct inode_operations > > > efivarfs_file_inode_operations = { > > > .fileattr_get = efivarfs_fileattr_get, > > > .fileattr_set = efivarfs_fileattr_set, > > > + .setattr = efivarfs_setattr, > > > }; > > > > Is it sufficient to just ignore inode size changes? > > Yes, as far as my testing goes. > > > Should we complain about this instead? > > I don't think so because every variable write (at least from the shell) > tends to start off with a truncation so we'd get a lot of spurious > complaints. > Fair enough I'll queue these up - thanks. ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] selftests/efivarfs: add check for disallowing file truncation 2025-01-19 14:59 [PATCH 0/2] efivarfs: fix ability to mimic uncommitted variables James Bottomley 2025-01-19 14:59 ` [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache James Bottomley @ 2025-01-19 14:59 ` James Bottomley 1 sibling, 0 replies; 6+ messages in thread From: James Bottomley @ 2025-01-19 14:59 UTC (permalink / raw) To: linux-fsdevel, linux-efi Cc: Ard Biesheuvel, Jeremy Kerr, Christian Brauner, Al Viro Now that the ability of arbitrary writes to set the inode size is fixed, verify that a variable file accepts a truncation operation but does not change the stat size because of it. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> --- tools/testing/selftests/efivarfs/efivarfs.sh | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh index d374878cc0ba..96677282789b 100755 --- a/tools/testing/selftests/efivarfs/efivarfs.sh +++ b/tools/testing/selftests/efivarfs/efivarfs.sh @@ -202,6 +202,28 @@ test_invalid_filenames() exit $ret } +test_no_set_size() +{ + local attrs='\x07\x00\x00\x00' + local file=$efivarfs_mount/$FUNCNAME-$test_guid + local ret=0 + + printf "$attrs\x00" > $file + [ -e $file -a -s $file ] || exit 1 + chattr -i $file + : > $file + if [ $? != 0 ]; then + echo "variable file failed to accept truncation" + ret=1 + elif [ -e $file -a ! -s $file ]; then + echo "file can be truncated to zero size" + ret=1 + fi + rm $file || exit 1 + + exit $ret +} + check_prereqs rc=0 @@ -214,5 +236,6 @@ run_test test_zero_size_delete run_test test_open_unlink run_test test_valid_filenames run_test test_invalid_filenames +run_test test_no_set_size exit $rc -- 2.35.3 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-01-19 16:52 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-01-19 14:59 [PATCH 0/2] efivarfs: fix ability to mimic uncommitted variables James Bottomley 2025-01-19 14:59 ` [PATCH 1/2] efivarfs: prevent setting of zero size on the inodes in the cache James Bottomley 2025-01-19 16:32 ` Ard Biesheuvel 2025-01-19 16:48 ` James Bottomley 2025-01-19 16:52 ` Ard Biesheuvel 2025-01-19 14:59 ` [PATCH 2/2] selftests/efivarfs: add check for disallowing file truncation James Bottomley
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox