Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp4439185ybp; Mon, 14 Oct 2019 04:47:57 -0700 (PDT) X-Google-Smtp-Source: APXvYqxuf1m19V3l824p7+q9I0YcI4Twb2sxLwBQvugLr0CWln4LLL0Sap1GqaiUuN8VMOocPvHB X-Received: by 2002:a17:906:524b:: with SMTP id y11mr12431837ejm.82.1571053677834; Mon, 14 Oct 2019 04:47:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571053677; cv=none; d=google.com; s=arc-20160816; b=Gf385oG5ppxZMcS9/WCiQlGJNDJ7g3FdetBGRZSCRNTBJ5BhrHjyelZEqNtpotZzzT T3mX1OIwwHqfLJNePjP2vBZWu/TZQZdXLm/H2JnXeQE2wVdYiEJUraoISN9Oz2t41uWE ZGDWLrjSEp0Ik7pw/diUiENqLhdQE/vWpvqvT8+3wrbvBFli6+D/GYXCpwNovx6mlr4Q nuYjmFELc3Js37dLWosvejJWIDf4tDkcvHnXKLzKgyu+f0/4pjPXOWLgPUg4XoIhD/Pu mvqsQ2yjJeJO8Bcmz72ft6lRafSU3GyotajJmJ87Qnm/aAxGg+2z1+lBb2lUGkTNsCj3 MA4A== 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 :message-id:date:subject:cc:to:from; bh=6jagU12n0yKX6KZAmNAH+VCllKX5TThb8qhRJHAy8+Q=; b=aLvBgu5QmzbAHxl45ZMHulmauNveOvOuAvh3G4itBPJhEGo/pYNV6jQG+jakIUgEmy GQb1fBbmF8LtnCqX7euKh0i3NgQu7X74MQBh39nw4om3AbzuGjTotoPGyTGbvrUA0gcb LpRNQ0FfkYot59BanXm79MxoxY+7Cey2sSjHaCcUD5EtgEcjPknuvFQcOed1ndb/E2tI HipzwK00cNoryWR18HJQ7EZ+tobTvn8XyrqUNC2PepSNDyvtwd9G51YL2ShzEvR0A4Iy Ggr8Tr5kt5GhDj4sPfygmJBQvWOcJtD87VxLbptOewUjCjTQETVa6ZF2Eg1vwFhgRaUN yTEA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m12si10850779eja.9.2019.10.14.04.47.32; Mon, 14 Oct 2019 04:47:57 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730472AbfJNLqh (ORCPT + 99 others); Mon, 14 Oct 2019 07:46:37 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54018 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730593AbfJNLqh (ORCPT ); Mon, 14 Oct 2019 07:46:37 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A35CC801673; Mon, 14 Oct 2019 11:46:35 +0000 (UTC) Received: from thinkpad.redhat.com (ovpn-116-247.ams2.redhat.com [10.36.116.247]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5186619C6A; Mon, 14 Oct 2019 11:46:33 +0000 (UTC) From: Laurent Vivier To: linux-kernel@vger.kernel.org Cc: Matt Mackall , 'Linux Samsung SOC' , Marek Szyprowski , Herbert Xu , linux-crypto@vger.kernel.org, Laurent Vivier Subject: [PATCH] hwrng: core - Fix use-after-free warning in hwrng_register() Date: Mon, 14 Oct 2019 13:46:32 +0200 Message-Id: <20191014114632.10875-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.6.2 (mx1.redhat.com [10.5.110.67]); Mon, 14 Oct 2019 11:46:36 +0000 (UTC) Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Commit daae28debcb0 has moved add_early_randomness() out of the rng_mutex and tries to protect the reference of the new rng device by incrementing the reference counter. But in hwrng_register(), the function can be called with a new device that is not set as the current_rng device and the reference has not been initialized. This patch fixes the problem by not using the reference counter when the device is not the current one: the reference counter is only meaningful in the case of the current rng device and a device is not used if it is not the current one (except in hwrng_register()) The problem has been reported by Marek Szyprowski on ARM 32bit Exynos5420-based Chromebook Peach-Pit board: WARNING: CPU: 3 PID: 1 at lib/refcount.c:156 hwrng_register+0x13c/0x1b4 refcount_t: increment on 0; use-after-free. Modules linked in: CPU: 3 PID: 1 Comm: swapper/0 Not tainted 5.4.0-rc1-00061-gdaae28debcb0 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0xa8/0xd4) [] (dump_stack) from [] (__warn+0xf4/0x10c) [] (__warn) from [] (warn_slowpath_fmt+0x74/0xb8) [] (warn_slowpath_fmt) from [] (hwrng_register+0x13c/0x1b4) [] (hwrng_register) from [] (tpm_chip_register+0xc4/0x274) ... Reported-by: Marek Szyprowski Fixes: daae28debcb0 ("hwrng: core - move add_early_randomness() out of rng_mutex") Tested-by: Marek Szyprowski Signed-off-by: Laurent Vivier --- drivers/char/hw_random/core.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 29f50c045c92..d85c6e18a2d2 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -471,17 +471,15 @@ static void start_khwrngd(void) int hwrng_register(struct hwrng *rng) { int err = -EINVAL; - struct hwrng *old_rng, *new_rng, *tmp; + struct hwrng *tmp; struct list_head *rng_list_ptr; + bool is_new_current = false; if (!rng->name || (!rng->data_read && !rng->read)) goto out; mutex_lock(&rng_mutex); - old_rng = current_rng; - new_rng = NULL; - /* Must not register two RNGs with the same name. */ err = -EEXIST; list_for_each_entry(tmp, &rng_list, list) { @@ -500,9 +498,8 @@ int hwrng_register(struct hwrng *rng) } list_add_tail(&rng->list, rng_list_ptr); - err = 0; - if (!old_rng || - (!cur_rng_set_by_user && rng->quality > old_rng->quality)) { + if (!current_rng || + (!cur_rng_set_by_user && rng->quality > current_rng->quality)) { /* * Set new rng as current as the new rng source * provides better entropy quality and was not @@ -511,15 +508,14 @@ int hwrng_register(struct hwrng *rng) err = set_current_rng(rng); if (err) goto out_unlock; + /* to use current_rng in add_early_randomness() we need + * to take a ref + */ + is_new_current = true; + kref_get(&rng->ref); } - - new_rng = rng; - kref_get(&new_rng->ref); -out_unlock: mutex_unlock(&rng_mutex); - - if (new_rng) { - if (new_rng != old_rng || !rng->init) { + if (is_new_current || !rng->init) { /* * Use a new device's input to add some randomness to * the system. If this rng device isn't going to be @@ -527,10 +523,13 @@ int hwrng_register(struct hwrng *rng) * called yet by set_current_rng(); so only use the * randomness from devices that don't need an init callback */ - add_early_randomness(new_rng); - } - put_rng(new_rng); + add_early_randomness(rng); } + if (is_new_current) + put_rng(rng); + return 0; +out_unlock: + mutex_unlock(&rng_mutex); out: return err; } -- 2.21.0