Received: by 2002:a05:6a10:a0d1:0:0:0:0 with SMTP id j17csp2639656pxa; Mon, 17 Aug 2020 15:11:16 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxH8bqLqzEoRjtyfHJ2lw8pzJ4oSpRtwDdVUiZI+x+lK08wtlTqN/ilgqHNeWOWHkNaP5Hn X-Received: by 2002:aa7:da48:: with SMTP id w8mr16764989eds.329.1597702276449; Mon, 17 Aug 2020 15:11:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1597702276; cv=none; d=google.com; s=arc-20160816; b=GWk4znir8BBxgPwc0f0L7bU88CwEq7vt9dO6ynN+oyUmTmccYzLMnPUU0hL0+CJjhG M0YSbixfL8UzC7kJV1poc7gKQoyB5dlfmpaE+588Q2MUI4tPm3mkb/WlQlCckP0REbx3 9Cx/rVL+BGinHygZopvKqn9IspZKTRtmJbih2GYUJS7oEQjNUcNHmTWwUWLw9UvSZD4j D/JKYcp4gqx+RifgijCS7yRkPXIRU6vtreosbMwjuwXgPpFi/SOKk1/Mg6dF0kmFLePu 2lvdY7kZQN2Q7f8cUocmHemaHkmgX1edvKq2ycurHn4wCgtFTpNeNrAymMCATZReKeo0 qV0g== 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=L0XpiQjxZjMWB+aD4WcRfUQyMpCUDNNy+yQtHAGmj3k=; b=FhV4fDmGRElNypUniIOnJoKh6XP73JYSui1kP2L9y6leMbOLGPdbza9SkmQ0R2c5F5 5OyBMoDSqRbijtPrekzWAG7pFNT+Yy666DelerLZHniMm/q9H3p7bBKv61K4J6a1DrMs e9kqhI/I2a06RjvNcyDoLq7mSr39Zk+I3rzRDplBy7XfrFRfCyZxTBmcwCaS8xVOOJ8Q kMopIbSmf+rh7gBC8rL76RLIw3fnCwMHUln6fYAXabkHuA08fbBpxsII5v9NipfzWfHB QCsag5QKFJy9Vylso+Xi78Oy3sm5b9yHMlNTv8rE/VX2wzROZ6UfcArUYXAgb0BbPSZ+ 3Q7g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=R77keApC; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id k27si11447065ejc.447.2020.08.17.15.10.53; Mon, 17 Aug 2020 15:11:16 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=R77keApC; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388801AbgHQQpZ (ORCPT + 99 others); Mon, 17 Aug 2020 12:45:25 -0400 Received: from mail.kernel.org ([198.145.29.99]:47200 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730993AbgHQP75 (ORCPT ); Mon, 17 Aug 2020 11:59:57 -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 1BC0320729; Mon, 17 Aug 2020 15:59:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1597679996; bh=iVo0GPoeKyLafUTHicn9yxl086QZHMa+h8QT9zS3jU8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=R77keApCAfueAHqbsKmfgp25Acor7DNm4nPCcdiV8AZlPcc8rUIB8FG0cjSD7g9Ot VmMbs/Z8C8s9Um/ly/2wXHGXQ5XF1ZCiBn7Oma34a2nWDFc3S6PT9tVowG/cQUcMVQ P58G9pbsRkv1MXqGjCOT1G6lTR/LrWJbbgPHeBEA= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Herbert Xu , "Martin K. Petersen" , Eric Biggers , Sasha Levin Subject: [PATCH 5.4 013/270] crc-t10dif: Fix potential crypto notify dead-lock Date: Mon, 17 Aug 2020 17:13:34 +0200 Message-Id: <20200817143756.465955969@linuxfoundation.org> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200817143755.807583758@linuxfoundation.org> References: <20200817143755.807583758@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: Herbert Xu [ Upstream commit 3906f640224dbe7714b52b66d7d68c0812808e19 ] The crypto notify call occurs with a read mutex held so you must not do any substantial work directly. In particular, you cannot call crypto_alloc_* as they may trigger further notifications which may dead-lock in the presence of another writer. This patch fixes this by postponing the work into a work queue and taking the same lock in the module init function. While we're at it this patch also ensures that all RCU accesses are marked appropriately (tested with sparse). Finally this also reveals a race condition in module param show function as it may be called prior to the module init function. It's fixed by testing whether crct10dif_tfm is NULL (this is true iff the init function has not completed assuming fallback is false). Fixes: 11dcb1037f40 ("crc-t10dif: Allow current transform to be...") Fixes: b76377543b73 ("crc-t10dif: Pick better transform if one...") Signed-off-by: Herbert Xu Reviewed-by: Martin K. Petersen Reviewed-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- lib/crc-t10dif.c | 54 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/lib/crc-t10dif.c b/lib/crc-t10dif.c index 8cc01a6034165..c9acf1c12cfcb 100644 --- a/lib/crc-t10dif.c +++ b/lib/crc-t10dif.c @@ -19,39 +19,46 @@ static struct crypto_shash __rcu *crct10dif_tfm; static struct static_key crct10dif_fallback __read_mostly; static DEFINE_MUTEX(crc_t10dif_mutex); +static struct work_struct crct10dif_rehash_work; -static int crc_t10dif_rehash(struct notifier_block *self, unsigned long val, void *data) +static int crc_t10dif_notify(struct notifier_block *self, unsigned long val, void *data) { struct crypto_alg *alg = data; - struct crypto_shash *new, *old; if (val != CRYPTO_MSG_ALG_LOADED || static_key_false(&crct10dif_fallback) || strncmp(alg->cra_name, CRC_T10DIF_STRING, strlen(CRC_T10DIF_STRING))) return 0; + schedule_work(&crct10dif_rehash_work); + return 0; +} + +static void crc_t10dif_rehash(struct work_struct *work) +{ + struct crypto_shash *new, *old; + mutex_lock(&crc_t10dif_mutex); old = rcu_dereference_protected(crct10dif_tfm, lockdep_is_held(&crc_t10dif_mutex)); if (!old) { mutex_unlock(&crc_t10dif_mutex); - return 0; + return; } new = crypto_alloc_shash("crct10dif", 0, 0); if (IS_ERR(new)) { mutex_unlock(&crc_t10dif_mutex); - return 0; + return; } rcu_assign_pointer(crct10dif_tfm, new); mutex_unlock(&crc_t10dif_mutex); synchronize_rcu(); crypto_free_shash(old); - return 0; } static struct notifier_block crc_t10dif_nb = { - .notifier_call = crc_t10dif_rehash, + .notifier_call = crc_t10dif_notify, }; __u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len) @@ -86,19 +93,26 @@ EXPORT_SYMBOL(crc_t10dif); static int __init crc_t10dif_mod_init(void) { + struct crypto_shash *tfm; + + INIT_WORK(&crct10dif_rehash_work, crc_t10dif_rehash); crypto_register_notifier(&crc_t10dif_nb); - crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0); - if (IS_ERR(crct10dif_tfm)) { + mutex_lock(&crc_t10dif_mutex); + tfm = crypto_alloc_shash("crct10dif", 0, 0); + if (IS_ERR(tfm)) { static_key_slow_inc(&crct10dif_fallback); - crct10dif_tfm = NULL; + tfm = NULL; } + RCU_INIT_POINTER(crct10dif_tfm, tfm); + mutex_unlock(&crc_t10dif_mutex); return 0; } static void __exit crc_t10dif_mod_fini(void) { crypto_unregister_notifier(&crc_t10dif_nb); - crypto_free_shash(crct10dif_tfm); + cancel_work_sync(&crct10dif_rehash_work); + crypto_free_shash(rcu_dereference_protected(crct10dif_tfm, 1)); } module_init(crc_t10dif_mod_init); @@ -106,11 +120,27 @@ module_exit(crc_t10dif_mod_fini); static int crc_t10dif_transform_show(char *buffer, const struct kernel_param *kp) { + struct crypto_shash *tfm; + const char *name; + int len; + if (static_key_false(&crct10dif_fallback)) return sprintf(buffer, "fallback\n"); - return sprintf(buffer, "%s\n", - crypto_tfm_alg_driver_name(crypto_shash_tfm(crct10dif_tfm))); + rcu_read_lock(); + tfm = rcu_dereference(crct10dif_tfm); + if (!tfm) { + len = sprintf(buffer, "init\n"); + goto unlock; + } + + name = crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm)); + len = sprintf(buffer, "%s\n", name); + +unlock: + rcu_read_unlock(); + + return len; } module_param_call(transform, NULL, crc_t10dif_transform_show, NULL, 0644); -- 2.25.1