From: "tip-bot2 for Vladis Dronov" <tip-bot2@linutronix.de>
To: linux-tip-commits@vger.kernel.org
Cc: Bob Sanders <bob.sanders@hpe.com>,
Vladis Dronov <vdronov@redhat.com>,
Ard Biesheuvel <ardb@kernel.org>, Ingo Molnar <mingo@kernel.org>,
<stable@vger.kernel.org>, x86 <x86@kernel.org>,
LKML <linux-kernel@vger.kernel.org>
Subject: [tip: efi/urgent] efi: Fix a race and a buffer overflow while reading efivars via sysfs
Date: Sun, 08 Mar 2020 16:38:33 -0000 [thread overview]
Message-ID: <158368551309.28353.6521114137797916495.tip-bot2@tip-bot2> (raw)
In-Reply-To: <20200305084041.24053-2-vdronov@redhat.com>
The following commit has been merged into the efi/urgent branch of tip:
Commit-ID: 286d3250c9d6437340203fb64938bea344729a0e
Gitweb: https://git.kernel.org/tip/286d3250c9d6437340203fb64938bea344729a0e
Author: Vladis Dronov <vdronov@redhat.com>
AuthorDate: Sun, 08 Mar 2020 09:08:54 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Sun, 08 Mar 2020 09:56:34 +01:00
efi: Fix a race and a buffer overflow while reading efivars via sysfs
There is a race and a buffer overflow corrupting a kernel memory while
reading an EFI variable with a size more than 1024 bytes via the older
sysfs method. This happens because accessing struct efi_variable in
efivar_{attr,size,data}_read() and friends is not protected from
a concurrent access leading to a kernel memory corruption and, at best,
to a crash. The race scenario is the following:
CPU0: CPU1:
efivar_attr_read()
var->DataSize = 1024;
efivar_entry_get(... &var->DataSize)
down_interruptible(&efivars_lock)
efivar_attr_read() // same EFI var
var->DataSize = 1024;
efivar_entry_get(... &var->DataSize)
down_interruptible(&efivars_lock)
virt_efi_get_variable()
// returns EFI_BUFFER_TOO_SMALL but
// var->DataSize is set to a real
// var size more than 1024 bytes
up(&efivars_lock)
virt_efi_get_variable()
// called with var->DataSize set
// to a real var size, returns
// successfully and overwrites
// a 1024-bytes kernel buffer
up(&efivars_lock)
This can be reproduced by concurrent reading of an EFI variable which size
is more than 1024 bytes:
ts# for cpu in $(seq 0 $(nproc --ignore=1)); do ( taskset -c $cpu \
cat /sys/firmware/efi/vars/KEKDefault*/size & ) ; done
Fix this by using a local variable for a var's data buffer size so it
does not get overwritten.
Fixes: e14ab23dde12b80d ("efivars: efivar_entry API")
Reported-by: Bob Sanders <bob.sanders@hpe.com> and the LTP testsuite
Signed-off-by: Vladis Dronov <vdronov@redhat.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20200305084041.24053-2-vdronov@redhat.com
Link: https://lore.kernel.org/r/20200308080859.21568-24-ardb@kernel.org
---
drivers/firmware/efi/efivars.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 7576450..69f13bc 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -83,13 +83,16 @@ static ssize_t
efivar_attr_read(struct efivar_entry *entry, char *buf)
{
struct efi_variable *var = &entry->var;
+ unsigned long size = sizeof(var->Data);
char *str = buf;
+ int ret;
if (!entry || !buf)
return -EINVAL;
- var->DataSize = 1024;
- if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+ ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+ var->DataSize = size;
+ if (ret)
return -EIO;
if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
@@ -116,13 +119,16 @@ static ssize_t
efivar_size_read(struct efivar_entry *entry, char *buf)
{
struct efi_variable *var = &entry->var;
+ unsigned long size = sizeof(var->Data);
char *str = buf;
+ int ret;
if (!entry || !buf)
return -EINVAL;
- var->DataSize = 1024;
- if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+ ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+ var->DataSize = size;
+ if (ret)
return -EIO;
str += sprintf(str, "0x%lx\n", var->DataSize);
@@ -133,12 +139,15 @@ static ssize_t
efivar_data_read(struct efivar_entry *entry, char *buf)
{
struct efi_variable *var = &entry->var;
+ unsigned long size = sizeof(var->Data);
+ int ret;
if (!entry || !buf)
return -EINVAL;
- var->DataSize = 1024;
- if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+ ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+ var->DataSize = size;
+ if (ret)
return -EIO;
memcpy(buf, var->Data, var->DataSize);
@@ -250,14 +259,16 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
{
struct efi_variable *var = &entry->var;
struct compat_efi_variable *compat;
+ unsigned long datasize = sizeof(var->Data);
size_t size;
+ int ret;
if (!entry || !buf)
return 0;
- var->DataSize = 1024;
- if (efivar_entry_get(entry, &entry->var.Attributes,
- &entry->var.DataSize, entry->var.Data))
+ ret = efivar_entry_get(entry, &var->Attributes, &datasize, var->Data);
+ var->DataSize = datasize;
+ if (ret)
return -EIO;
if (in_compat_syscall()) {
next prev parent reply other threads:[~2020-03-08 16:38 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-03 8:55 [PATCH] efi: fix " Vladis Dronov
2020-03-03 9:15 ` Ard Biesheuvel
2020-03-03 10:14 ` Vladis Dronov
2020-03-03 10:20 ` Ard Biesheuvel
2020-03-03 10:24 ` Vladis Dronov
2020-03-04 6:51 ` joeyli
2020-03-04 15:45 ` Vladis Dronov
2020-03-04 15:47 ` Ard Biesheuvel
2020-03-04 15:49 ` [PATCH v2] " Vladis Dronov
2020-03-04 15:57 ` Ard Biesheuvel
2020-03-04 17:18 ` Vladis Dronov
2020-03-04 17:21 ` Ard Biesheuvel
2020-03-05 6:01 ` joeyli
2020-03-05 6:17 ` Vladis Dronov
2020-03-05 8:40 ` [PATCH v3 0/3] efi: fix a race and add a sanity check Vladis Dronov
2020-03-05 8:40 ` [PATCH v3 1/3] efi: fix a race and a buffer overflow while reading efivars via sysfs Vladis Dronov
2020-03-05 8:45 ` Ard Biesheuvel
2020-03-05 10:52 ` Vladis Dronov
2020-03-08 16:38 ` tip-bot2 for Vladis Dronov [this message]
2020-03-05 8:40 ` [PATCH v3 2/3] efi: add a sanity check to efivar_store_raw() Vladis Dronov
2020-03-08 16:38 ` [tip: efi/urgent] efi: Add " tip-bot2 for Vladis Dronov
2020-03-05 8:40 ` [PATCH v3 3/3] efi: fix a mistype in comments mentioning efivar_entry_iter_begin() Vladis Dronov
2020-03-05 8:51 ` [PATCH v3 0/3] efi: fix a race and add a sanity check Ard Biesheuvel
2020-03-04 14:07 ` [PATCH] efi: fix a race and a buffer overflow while reading efivars via sysfs joeyli
2020-03-04 16:06 ` Vladis Dronov
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=158368551309.28353.6521114137797916495.tip-bot2@tip-bot2 \
--to=tip-bot2@linutronix.de \
--cc=ardb@kernel.org \
--cc=bob.sanders@hpe.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tip-commits@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=stable@vger.kernel.org \
--cc=vdronov@redhat.com \
--cc=x86@kernel.org \
/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
all inboxes | Powered by JetHome®