Skip to content

Commit 9cb636b

Browse files
V4belardbiesheuvel
authored andcommitted
efi: capsule-loader: Fix use-after-free in efi_capsule_write
A race condition may occur if the user calls close() on another thread during a write() operation on the device node of the efi capsule. This is a race condition that occurs between the efi_capsule_write() and efi_capsule_flush() functions of efi_capsule_fops, which ultimately results in UAF. So, the page freeing process is modified to be done in efi_capsule_release() instead of efi_capsule_flush(). Cc: <[email protected]> # v4.9+ Signed-off-by: Hyunwoo Kim <[email protected]> Link: https://lore.kernel.org/all/20220907102920.GA88602@ubuntu/ Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 7a1ec84 commit 9cb636b

File tree

1 file changed

+7
-24
lines changed

1 file changed

+7
-24
lines changed

drivers/firmware/efi/capsule-loader.c

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -242,29 +242,6 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
242242
return ret;
243243
}
244244

245-
/**
246-
* efi_capsule_flush - called by file close or file flush
247-
* @file: file pointer
248-
* @id: not used
249-
*
250-
* If a capsule is being partially uploaded then calling this function
251-
* will be treated as upload termination and will free those completed
252-
* buffer pages and -ECANCELED will be returned.
253-
**/
254-
static int efi_capsule_flush(struct file *file, fl_owner_t id)
255-
{
256-
int ret = 0;
257-
struct capsule_info *cap_info = file->private_data;
258-
259-
if (cap_info->index > 0) {
260-
pr_err("capsule upload not complete\n");
261-
efi_free_all_buff_pages(cap_info);
262-
ret = -ECANCELED;
263-
}
264-
265-
return ret;
266-
}
267-
268245
/**
269246
* efi_capsule_release - called by file close
270247
* @inode: not used
@@ -277,6 +254,13 @@ static int efi_capsule_release(struct inode *inode, struct file *file)
277254
{
278255
struct capsule_info *cap_info = file->private_data;
279256

257+
if (cap_info->index > 0 &&
258+
(cap_info->header.headersize == 0 ||
259+
cap_info->count < cap_info->total_size)) {
260+
pr_err("capsule upload not complete\n");
261+
efi_free_all_buff_pages(cap_info);
262+
}
263+
280264
kfree(cap_info->pages);
281265
kfree(cap_info->phys);
282266
kfree(file->private_data);
@@ -324,7 +308,6 @@ static const struct file_operations efi_capsule_fops = {
324308
.owner = THIS_MODULE,
325309
.open = efi_capsule_open,
326310
.write = efi_capsule_write,
327-
.flush = efi_capsule_flush,
328311
.release = efi_capsule_release,
329312
.llseek = no_llseek,
330313
};

0 commit comments

Comments
 (0)