From patchwork Sun Jun 3 23:28:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Teddy Reed X-Patchwork-Id: 924783 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Vjf/JeTy"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40zZ4k3TmGz9ryk for ; Mon, 4 Jun 2018 09:28:21 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id AA5DCC21E76; Sun, 3 Jun 2018 23:28:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id C1107C21D56; Sun, 3 Jun 2018 23:28:06 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 8504FC21D56; Sun, 3 Jun 2018 23:28:05 +0000 (UTC) Received: from mail-qt0-f195.google.com (mail-qt0-f195.google.com [209.85.216.195]) by lists.denx.de (Postfix) with ESMTPS id DE670C21C8B for ; Sun, 3 Jun 2018 23:28:04 +0000 (UTC) Received: by mail-qt0-f195.google.com with SMTP id i18-v6so28001351qtp.12 for ; Sun, 03 Jun 2018 16:28:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:mime-version :content-transfer-encoding; bh=YEzRltBBNKoX68QsK+WpyNGFuL7enDm4QuVGvP0K6po=; b=Vjf/JeTypr6voeKSufO6q3sV1YyRyEMBOmgeJ5JcXYwYWylV1qFS0R1bXrXWNecU89 p0rRfAB2dTZcnn/mG3z2E4cD8Jlx/5iArrUwm9ZD4BqoXhzA9gFFg+/WNnXjh5Fi9bnB ttdVp7VapIl6OYUU2+fpCCsXLgJ/fAVJ24CrKCFtOFBemLbF7kf6unenA76UUTmHsg48 6eUq9gSLQQteb9pfXxjgdrEZXjtkqgIRVxW3iR2oKKG/U1l8eQP9UvoVVAK37VpNqO4K vUEDGxx/L56nwLkOQkzyhd0t8PnDyGxOEee9k8/eOB+cWIVH/vFW6J8zxZ5TKAuZ2hft JdkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-transfer-encoding; bh=YEzRltBBNKoX68QsK+WpyNGFuL7enDm4QuVGvP0K6po=; b=W71ANNag2ErAS35kbJLXs1mxWe6Zc3dbumhXEKGzhNlUDU1kWnSqMXqB7dYKuD9kxa EFRyOLyrUbUXBqulNpizZopAHVTVSMPv0SMraL45tEV1l+DQEKcB/Q/qTl22ScKa7mmT hZJcf5mkRqc9OVFVLok2wxX+KbQOsmmNcuYWc4ooN8GrbGkWCNAg5HniXmnIYdvRLY6z lE/koN0BjC/NDfjoBSPq9f55m1RaFDf0OdzeZpyRqc71T+JfpBWHkOpJ9uE6g/O3T3qI UiOGI4/ktwpiCGAOFZm9jbEsakBess9hDaOgd/CWd9A5XPODkNLnl7LZfVizBKkJjyXa x70A== X-Gm-Message-State: APt69E0USo4R3ac4yKsJz35DNezLWv2lfRb53wLuDYH0qIIcM2510lv1 eFrosnVFQYcuGPZbowoiIAWYKh/Z X-Google-Smtp-Source: ADUXVKL6qLlPKsVAOcWOlWMdlNlyG+HFv/x3qeesVKpF5MpuQqqvGdOWs+v7sbLZ2OaVC6Oq6AG3Sg== X-Received: by 2002:a0c:f94d:: with SMTP id i13-v6mr14164574qvo.95.1528068483425; Sun, 03 Jun 2018 16:28:03 -0700 (PDT) Received: from maverics (pool-108-35-88-207.nwrknj.fios.verizon.net. [108.35.88.207]) by smtp.gmail.com with ESMTPSA id b10-v6sm31775141qti.45.2018.06.03.16.28.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 03 Jun 2018 16:28:02 -0700 (PDT) Date: Sun, 3 Jun 2018 19:28:02 -0400 From: Teddy Reed To: u-boot@lists.denx.de Message-Id: <20180603192802.097817042230c5b98e3a506b@gmail.com> X-Mailer: Sylpheed 3.5.0 (GTK+ 2.24.30; x86_64-pc-linux-gnu) Mime-Version: 1.0 Subject: [U-Boot] [PATCH] vboot: Add FIT_SIGNATURE_MAX_SIZE protection X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" This adds a new config value FIT_SIGNATURE_MAX_SIZE, which controls the max size of a FIT header's totalsize field. The max size is checked before signature checks are applied to prevent reading past defined FIT regions. This field is not part of the vboot signature so it should be sanity checked. If the field is corrupted then the structure or string region reads may have unintended behavior, such as reading from device memory. A default value of 256MB is set and intended to support most max storage sizes. Suggested-by: Simon Glass Signed-off-by: Teddy Reed Reviewed-by: Simon Glass --- Kconfig | 10 ++++++++++ common/image-sig.c | 7 +++++++ test/py/tests/test_vboot.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/Kconfig b/Kconfig index 5a82c95..c8b86cd 100644 --- a/Kconfig +++ b/Kconfig @@ -267,6 +267,16 @@ config FIT_SIGNATURE format support in this case, enable it using CONFIG_IMAGE_FORMAT_LEGACY. +config FIT_SIGNATURE_MAX_SIZE + hex "Max size of signed FIT structures" + depends on FIT_SIGNATURE + default 0x10000000 + help + This option sets a max size in bytes for verified FIT uImages. + A sane value of 256MB protects corrupted DTB structures from overlapping + device memory. Assure this size does not extend past expected storage + space. + config FIT_VERBOSE bool "Show verbose messages when FIT images fail" help diff --git a/common/image-sig.c b/common/image-sig.c index f65d883..e67d2a2 100644 --- a/common/image-sig.c +++ b/common/image-sig.c @@ -156,6 +156,13 @@ static int fit_image_setup_verify(struct image_sign_info *info, { char *algo_name; +#ifdef CONFIG_FIT_SIGNATURE_MAX_SIZE + if (fdt_totalsize(fit) > CONFIG_FIT_SIGNATURE_MAX_SIZE) { + *err_msgp = "Total size too large"; + return -1; + } +#endif + if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { *err_msgp = "Can't get hash algo property"; return -1; diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py index ee939f2..7b986d2 100644 --- a/test/py/tests/test_vboot.py +++ b/test/py/tests/test_vboot.py @@ -26,6 +26,7 @@ Tests run with both SHA1 and SHA256 hashing. import pytest import sys +import struct import u_boot_utils as util @pytest.mark.boardspec('sandbox') @@ -105,6 +106,26 @@ def test_vboot(u_boot_console): util.run_and_log(cons, [mkimage, '-F', '-k', tmpdir, '-K', dtb, '-r', fit]) + def replace_fit_totalsize(size): + """Replace FIT header's totalsize. + + The totalsize must be less than or equal to FIT_SIGNATURE_MAX_SIZE. + If the size is greater, the signature verification should return false. + + Args: + size: The new totalsize of the header. + + Returns: + prev_size: The previous totalsize read from the header. + """ + total_size = 0 + with open(fit, 'r+b') as handle: + handle.seek(4) + total_size = handle.read(4) + handle.seek(4) + handle.write(struct.pack(">I", size)) + return struct.unpack(">I", total_size)[0] + def test_with_algo(sha_algo): """Test verified boot with the given hash algorithm. @@ -146,6 +167,16 @@ def test_vboot(u_boot_console): util.run_and_log(cons, [fit_check_sign, '-f', fit, '-k', tmpdir, '-k', dtb]) + # Replace header bytes + existing_size = replace_fit_totalsize(256 * 1024 * 1024 + 1) + run_bootm(sha_algo, 'Signed config with bad hash', 'Bad Data Hash', False) + cons.log.action('%s: Check overflowed FIT header totalsize' % sha_algo) + + # Replace with existing header bytes + replace_fit_totalsize(existing_size) + run_bootm(sha_algo, 'signed config', 'dev+', True) + cons.log.action('%s: Check default FIT header totalsize' % sha_algo) + # Increment the first byte of the signature, which should cause failure sig = util.run_and_log(cons, 'fdtget -t bx %s %s value' % (fit, sig_node))