Received: by 2002:a25:d783:0:0:0:0:0 with SMTP id o125csp658550ybg; Thu, 19 Mar 2020 06:32:45 -0700 (PDT) X-Google-Smtp-Source: ADFU+vsoR9f510qLeoK4SNRLtiUVBJSff71D3/wabaKU96Q7Tl5ECf0SZJM8OBg3VfDy7fOA/nYK X-Received: by 2002:a05:6830:120f:: with SMTP id r15mr2265646otp.90.1584624765605; Thu, 19 Mar 2020 06:32:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1584624765; cv=none; d=google.com; s=arc-20160816; b=YkHjiyOEgbPC+Bj2BuvYISmCGxxWnhE9YybptrT3Rl8hOpx7THoqTfqPLfjMTuQlCB HcJKAtk+4ICU7xnZywWqdn3QcLXYssv0xMYP+zHUsvfxRFJBlXCuUpFa7BhjPBztyjIL 0qZ1yHXZtSla/8P36KwCuNu2IF7WFtR5cIexbxj4kqvCA1FjrHzWIyTNHp6XmT4kiYt7 rHueo7qcDMIWBejrJcE0V24O3U8DuIZ/e9+vQA9Zr7fFICRA/6MgYlGm08cQjmCmalC4 OLX8DwSRXbXxXWxYwAe4nssSmUHk2JHcQnCNIUk9fKO+FsL8v4fMx+CptnXaxo25y890 p4mg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=0p9zeUtu2WRqf/2eS3PSYr6v0zFaQiiKFQMUSQRkwko=; b=wGHhomd8OvmKdwha2xAYkLUBJmKiy+xUffKbSbpNKRfRpmbVC+d+Q9edym3bXmjsom SS9/cLPXE68TEHkBJ+bIV79NE/w466/QCNOIAnC/yTZROoaeGcRkKsYM5krrl8/ynr9S 8bYjoOOVReBcAqO+r3I+qwofwoCPlPe/gqsD/NRwQwgyZ5cil6WXWPkkzN4ZNPERiJAv +PE9il45swT7OIP8HtWjgUbkvTyBFaIgeKweZ3pji8Cb8MCp0whIyn9R9mdaqHGoveC3 rgZocbdf2WiWyeVTUbXo2UGS7BeLlz3K5eWbNCkKBypqXuylQuBLXNqwPgm3b3270SLG rINA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=Ahvrs+VP; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e24si1266724oti.10.2020.03.19.06.32.32; Thu, 19 Mar 2020 06:32:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=Ahvrs+VP; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729517AbgCSNQP (ORCPT + 99 others); Thu, 19 Mar 2020 09:16:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:36422 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729483AbgCSNQN (ORCPT ); Thu, 19 Mar 2020 09:16:13 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id B4A5720724; Thu, 19 Mar 2020 13:16:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1584623772; bh=Q5wpVU1xu8wGACPp+m7pI66Up6viVKtEFbyPFoD1gG0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ahvrs+VPgSYQu6KAC63ox+evZh6b0XhRi4hP8cFoIhhivsYlg1z0VrB0tszbkD7IX FFCaYHt53XaLGkALfphY3jn6WK1i3AVQVA2DzeBIs/mKSzO65YpfEt3lKN+dwBf0ER EIYs8h06EpVQg1fFlb/aW5mvoCF34ZEhOGq9yTeU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Vladis Dronov , Ard Biesheuvel , Ingo Molnar , Bob Sanders Subject: [PATCH 4.14 49/99] efi: Fix a race and a buffer overflow while reading efivars via sysfs Date: Thu, 19 Mar 2020 14:03:27 +0100 Message-Id: <20200319123956.785011253@linuxfoundation.org> X-Mailer: git-send-email 2.25.2 In-Reply-To: <20200319123941.630731708@linuxfoundation.org> References: <20200319123941.630731708@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Vladis Dronov commit 286d3250c9d6437340203fb64938bea344729a0e upstream. 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 and the LTP testsuite Signed-off-by: Vladis Dronov Signed-off-by: Ard Biesheuvel Signed-off-by: Ingo Molnar Cc: Link: https://lore.kernel.org/r/20200305084041.24053-2-vdronov@redhat.com Link: https://lore.kernel.org/r/20200308080859.21568-24-ardb@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/efi/efivars.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -139,13 +139,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) @@ -172,13 +175,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); @@ -189,12 +195,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); @@ -314,14 +323,16 @@ efivar_show_raw(struct efivar_entry *ent { 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 (is_compat()) {