efivarfs: allow creation of zero length files
authorJames Bottomley <James.Bottomley@HansenPartnership.com>
Wed, 26 Feb 2025 21:48:26 +0000 (16:48 -0500)
committerArd Biesheuvel <ardb@kernel.org>
Thu, 27 Feb 2025 10:27:49 +0000 (11:27 +0100)
Temporarily allow the creation of zero length files in efivarfs so the
'fwupd' user space firmware update tool can continue to operate. This
hack should be reverted as soon as the fwupd mechanisms for updating
firmware have been fixed.

fwupd has been coded to open a firmware file, close it, remove the
immutable bit and write to it.  Since commit 908af31f4896 ("efivarfs:
fix error on write to new variable leaving remnants") this behaviour
results in the first close removing the file which causes the second
write to fail.  To allow fwupd to keep working code up an indicator of
size 1 if a write fails and only remove the file on that condition (so
create at zero size is allowed).

Tested-by: Richard Hughes <richard@hughsie.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
[ardb: replace LVFS with fwupd, as suggested by Richard]
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
fs/efivarfs/file.c

index cb1b6d0c34545c701ca36bc881ee922d1ff41bac..c294a8fc566da5a351f22cf33084540edf68383b 100644 (file)
@@ -57,10 +57,11 @@ static ssize_t efivarfs_file_write(struct file *file,
 
        if (bytes == -ENOENT) {
                /*
-                * zero size signals to release that the write deleted
-                * the variable
+                * FIXME: temporary workaround for fwupdate, signal
+                * failed write with a 1 to keep created but not
+                * written files
                 */
-               i_size_write(inode, 0);
+               i_size_write(inode, 1);
        } else {
                i_size_write(inode, datasize + sizeof(attributes));
                inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
@@ -124,7 +125,8 @@ static int efivarfs_file_release(struct inode *inode, struct file *file)
        struct efivar_entry *var = inode->i_private;
 
        inode_lock(inode);
-       var->removed = (--var->open_count == 0 && i_size_read(inode) == 0);
+       /* FIXME: temporary work around for fwupdate */
+       var->removed = (--var->open_count == 0 && i_size_read(inode) == 1);
        inode_unlock(inode);
 
        if (var->removed)