Received: by 2002:a25:b323:0:0:0:0:0 with SMTP id l35csp356960ybj; Thu, 19 Sep 2019 15:39:53 -0700 (PDT) X-Google-Smtp-Source: APXvYqzYFBNpzp91aONle2Yin90ZUZMOrOps0p5p91IUa6UMxpC4w7q9UWOpR8/UlhKnxUxzFypY X-Received: by 2002:a17:906:3286:: with SMTP id 6mr3795875ejw.37.1568932793003; Thu, 19 Sep 2019 15:39:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1568932792; cv=none; d=google.com; s=arc-20160816; b=h+tr3MAtdxPP5vrYli73TvuAPxJkuS7WkM+3od1vm9GQzg02hhX9Dcm8jdX1tsoui1 2JvBSoFa8MeR1EqTUnauIZI+j6KaboJhN3pnor7F/Q+to40Q7b6ZwaHGEAA7fwXXQkk+ 5X5P7Jmpio0dlCIapXYdfbBSsUvjhSxycBhYbmcvQ87kXWs1JPBWsstYq4MZ2cfyiVm9 1/N7iQAoi0DImliDBbhYUFnFUEbacrjsZecnUVD81uFO86bd7QM0UVxUX9xSM7IO00OW ZD+REQoKaiVTADBotV3hKhdwekLydNb0MkbDu3xNRDFNsfL2kwzuCAW8CoDeqDpUYZW9 yuKw== 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=kIDN29hcb5Z8gWOZt5gsrcTCbLRav17DBmUffql1rpA=; b=YqOT6liPpwHsBaHi3aJM81xIquhA2TxM/PBdpZBe4s48H8pWCkFj+e+Snmc4tISy70 rg7JH85hjKjK6tCb2tOV+vI57qvaHmseGzyKiCniRHirF8ofyi+QmUp7H+fodAY0KYSC Ru+L1xbHYe+qeR6aloQT2SV2QTIwIb7aZqF3KJwM2i7oJazSyS64oVjK6tLUMi5FFPvN So+gyxywirlElJbp1FCb7+3c/omxb8EexB9Xb2jllKoTE2ZOFaXXVTm5z2sAchHisZ+6 Vf8FOuRhlqRGyEFXSM5VjDC+pNSTaKYWBcK3i7Hconb0po9yrN2YqwVDMI7O8Q+vtcyo vljw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=R2ZG+Xs5; 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 a54si92847edc.333.2019.09.19.15.39.30; Thu, 19 Sep 2019 15:39:52 -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=R2ZG+Xs5; 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 S2406167AbfISWPk (ORCPT + 99 others); Thu, 19 Sep 2019 18:15:40 -0400 Received: from mail.kernel.org ([198.145.29.99]:55560 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2403915AbfISWPi (ORCPT ); Thu, 19 Sep 2019 18:15:38 -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 D773A218AF; Thu, 19 Sep 2019 22:15:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1568931337; bh=yoIrDO0cf+GaDOLoHFCRsXHjgRGCbBc+beEhYdSyiCQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=R2ZG+Xs5hnA6BbKUp9OPig06fyiYMFVyY8Xjq8Q7XNoL66mKGRhs1E0itm5PnhD75 phom0VmPcSAbVQ/JwkiSB8zwtVnsXymkYMSLjNlYP8bg6Hth2Rd1MByMnjlFheYPga /jNzFrie0hot6S6tPQMGDpmyM2ZKk/Icimey3pEc= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Hung-Te Lin , Guenter Roeck , Stephen Boyd Subject: [PATCH 4.14 10/59] firmware: google: check if size is valid when decoding VPD data Date: Fri, 20 Sep 2019 00:03:25 +0200 Message-Id: <20190919214758.196958344@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190919214755.852282682@linuxfoundation.org> References: <20190919214755.852282682@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: Hung-Te Lin commit 4b708b7b1a2c09fbdfff6b942ebe3a160213aacd upstream. The VPD implementation from Chromium Vital Product Data project used to parse data from untrusted input without checking if the meta data is invalid or corrupted. For example, the size from decoded content may be negative value, or larger than whole input buffer. Such invalid data may cause buffer overflow. To fix that, the size parameters passed to vpd_decode functions should be changed to unsigned integer (u32) type, and the parsing of entry header should be refactored so every size field is correctly verified before starting to decode. Fixes: ad2ac9d5c5e0 ("firmware: Google VPD: import lib_vpd source files") Signed-off-by: Hung-Te Lin Cc: stable Reviewed-by: Guenter Roeck Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20190830022402.214442-1-hungte@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/vpd.c | 4 +- drivers/firmware/google/vpd_decode.c | 55 ++++++++++++++++++++--------------- drivers/firmware/google/vpd_decode.h | 6 +-- 3 files changed, 37 insertions(+), 28 deletions(-) --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -100,8 +100,8 @@ static int vpd_section_check_key_name(co return VPD_OK; } -static int vpd_section_attrib_add(const u8 *key, s32 key_len, - const u8 *value, s32 value_len, +static int vpd_section_attrib_add(const u8 *key, u32 key_len, + const u8 *value, u32 value_len, void *arg) { int ret; --- a/drivers/firmware/google/vpd_decode.c +++ b/drivers/firmware/google/vpd_decode.c @@ -19,8 +19,8 @@ #include "vpd_decode.h" -static int vpd_decode_len(const s32 max_len, const u8 *in, - s32 *length, s32 *decoded_len) +static int vpd_decode_len(const u32 max_len, const u8 *in, + u32 *length, u32 *decoded_len) { u8 more; int i = 0; @@ -40,18 +40,39 @@ static int vpd_decode_len(const s32 max_ } while (more); *decoded_len = i; + return VPD_OK; +} + +static int vpd_decode_entry(const u32 max_len, const u8 *input_buf, + u32 *_consumed, const u8 **entry, u32 *entry_len) +{ + u32 decoded_len; + u32 consumed = *_consumed; + if (vpd_decode_len(max_len - consumed, &input_buf[consumed], + entry_len, &decoded_len) != VPD_OK) + return VPD_FAIL; + if (max_len - consumed < decoded_len) + return VPD_FAIL; + + consumed += decoded_len; + *entry = input_buf + consumed; + + /* entry_len is untrusted data and must be checked again. */ + if (max_len - consumed < *entry_len) + return VPD_FAIL; + + consumed += decoded_len; + *_consumed = consumed; return VPD_OK; } -int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed, +int vpd_decode_string(const u32 max_len, const u8 *input_buf, u32 *consumed, vpd_decode_callback callback, void *callback_arg) { int type; - int res; - s32 key_len; - s32 value_len; - s32 decoded_len; + u32 key_len; + u32 value_len; const u8 *key; const u8 *value; @@ -66,26 +87,14 @@ int vpd_decode_string(const s32 max_len, case VPD_TYPE_STRING: (*consumed)++; - /* key */ - res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], - &key_len, &decoded_len); - if (res != VPD_OK || *consumed + decoded_len >= max_len) + if (vpd_decode_entry(max_len, input_buf, consumed, &key, + &key_len) != VPD_OK) return VPD_FAIL; - *consumed += decoded_len; - key = &input_buf[*consumed]; - *consumed += key_len; - - /* value */ - res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], - &value_len, &decoded_len); - if (res != VPD_OK || *consumed + decoded_len > max_len) + if (vpd_decode_entry(max_len, input_buf, consumed, &value, + &value_len) != VPD_OK) return VPD_FAIL; - *consumed += decoded_len; - value = &input_buf[*consumed]; - *consumed += value_len; - if (type == VPD_TYPE_STRING) return callback(key, key_len, value, value_len, callback_arg); --- a/drivers/firmware/google/vpd_decode.h +++ b/drivers/firmware/google/vpd_decode.h @@ -33,8 +33,8 @@ enum { }; /* Callback for vpd_decode_string to invoke. */ -typedef int vpd_decode_callback(const u8 *key, s32 key_len, - const u8 *value, s32 value_len, +typedef int vpd_decode_callback(const u8 *key, u32 key_len, + const u8 *value, u32 value_len, void *arg); /* @@ -52,7 +52,7 @@ typedef int vpd_decode_callback(const u8 * If one entry is successfully decoded, sends it to callback and returns the * result. */ -int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed, +int vpd_decode_string(const u32 max_len, const u8 *input_buf, u32 *consumed, vpd_decode_callback callback, void *callback_arg); #endif /* __VPD_DECODE_H */