Received: by 2002:ac0:a581:0:0:0:0:0 with SMTP id m1-v6csp2984047imm; Sun, 1 Jul 2018 09:41:35 -0700 (PDT) X-Google-Smtp-Source: AAOMgpc3Uq6DUNLj6/PruSlS2AIw6QOIgHtSkAtR2NXgAyhgDuSPPW2U9jZvhI5jZH6J2uKmmLWu X-Received: by 2002:aa7:8058:: with SMTP id y24-v6mr22167428pfm.148.1530463295564; Sun, 01 Jul 2018 09:41:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530463295; cv=none; d=google.com; s=arc-20160816; b=bYRYhE/yjSK/GcHY+/30wIxTexhU0a8aStscjz5uoi76boUCGUkoNskOtSwn2iOzOw Niq+ecm7dsQw3c4NBmyzlube9HBwRDg5pvzLQkNiIGeAU+e6d8+yR0jmPEOGbggvtT9j hD/Ixryhn+bfOW4ayrXGuMyG16bKcFpGI/eLiz+Hv3djE/BapLPxhF9gyIOrvU5Aqfar bo8N/rus2+PJdUlAFtAKeiTd9iMlQUv+VIhOTJ5PIICgWq4qlUZwsuppsdFCd548ew1B KvPzVaNM8DWFKLNqhItrS1SwZbeFkMNTeLuHR0AlKvIEwOxYhfT0VxhUGoi4tB81bSws nCBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=+2QfuDrwIyHvBSH3TpPW5CSngj2bhTS7wUPViQaNLB0=; b=wxC9Klitcukk8AwZVqyKUYsCylnY9fEDH8px+XchjiSUyJpXWEzwXEh8ihC2Jn59z/ ny2LCc0R2VhuAgL5mceyR/fYDc+eT3xJcZjSmPevu/situzLCjI7rcDK23YTGL7nT4NP d+9m4FlRa/5tb7bgOB8te/YLKPtPNQyifjg8B8bQS7LStV/0GipTZUAVUND6tdP4cmd4 nLXuUD1OcB+qb2uhbjG719OQxwBl5D9Lc27XRwazdrgNWYze584NcI7vxDxTbC5xLD5u oEsie6sqc8brxXisZ0bPjW03WvYQQ5aykg29FjA3pYz2pydRNK3GcaEywTBr66g84Bca PRyA== ARC-Authentication-Results: i=1; mx.google.com; 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 t1-v6si13647450plo.241.2018.07.01.09.41.21; Sun, 01 Jul 2018 09:41:35 -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; 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 S1031893AbeGAQkX (ORCPT + 99 others); Sun, 1 Jul 2018 12:40:23 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:37144 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1031867AbeGAQkQ (ORCPT ); Sun, 1 Jul 2018 12:40:16 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 7842FAA6; Sun, 1 Jul 2018 16:40:15 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Tadeusz Struk , Jarkko Sakkinen Subject: [PATCH 4.17 082/220] tpm: fix race condition in tpm_common_write() Date: Sun, 1 Jul 2018 18:21:46 +0200 Message-Id: <20180701160911.860229040@linuxfoundation.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180701160908.272447118@linuxfoundation.org> References: <20180701160908.272447118@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.17-stable review patch. If anyone has any objections, please let me know. ------------------ From: Tadeusz Struk commit 3ab2011ea368ec3433ad49e1b9e1c7b70d2e65df upstream. There is a race condition in tpm_common_write function allowing two threads on the same /dev/tpm, or two different applications on the same /dev/tpmrm to overwrite each other commands/responses. Fixed this by taking the priv->buffer_mutex early in the function. Also converted the priv->data_pending from atomic to a regular size_t type. There is no need for it to be atomic since it is only touched under the protection of the priv->buffer_mutex. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Tadeusz Struk Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-dev-common.c | 40 +++++++++++++++++--------------------- drivers/char/tpm/tpm-dev.h | 2 - 2 files changed, 19 insertions(+), 23 deletions(-) --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -37,7 +37,7 @@ static void timeout_work(struct work_str struct file_priv *priv = container_of(work, struct file_priv, work); mutex_lock(&priv->buffer_mutex); - atomic_set(&priv->data_pending, 0); + priv->data_pending = 0; memset(priv->data_buffer, 0, sizeof(priv->data_buffer)); mutex_unlock(&priv->buffer_mutex); } @@ -46,7 +46,6 @@ void tpm_common_open(struct file *file, struct file_priv *priv) { priv->chip = chip; - atomic_set(&priv->data_pending, 0); mutex_init(&priv->buffer_mutex); timer_setup(&priv->user_read_timer, user_reader_timeout, 0); INIT_WORK(&priv->work, timeout_work); @@ -58,29 +57,24 @@ ssize_t tpm_common_read(struct file *fil size_t size, loff_t *off) { struct file_priv *priv = file->private_data; - ssize_t ret_size; - ssize_t orig_ret_size; + ssize_t ret_size = 0; int rc; del_singleshot_timer_sync(&priv->user_read_timer); flush_work(&priv->work); - ret_size = atomic_read(&priv->data_pending); - if (ret_size > 0) { /* relay data */ - orig_ret_size = ret_size; - if (size < ret_size) - ret_size = size; + mutex_lock(&priv->buffer_mutex); - mutex_lock(&priv->buffer_mutex); + if (priv->data_pending) { + ret_size = min_t(ssize_t, size, priv->data_pending); rc = copy_to_user(buf, priv->data_buffer, ret_size); - memset(priv->data_buffer, 0, orig_ret_size); + memset(priv->data_buffer, 0, priv->data_pending); if (rc) ret_size = -EFAULT; - mutex_unlock(&priv->buffer_mutex); + priv->data_pending = 0; } - atomic_set(&priv->data_pending, 0); - + mutex_unlock(&priv->buffer_mutex); return ret_size; } @@ -91,17 +85,19 @@ ssize_t tpm_common_write(struct file *fi size_t in_size = size; ssize_t out_size; + if (in_size > TPM_BUFSIZE) + return -E2BIG; + + mutex_lock(&priv->buffer_mutex); + /* Cannot perform a write until the read has cleared either via * tpm_read or a user_read_timer timeout. This also prevents split * buffered writes from blocking here. */ - if (atomic_read(&priv->data_pending) != 0) + if (priv->data_pending != 0) { + mutex_unlock(&priv->buffer_mutex); return -EBUSY; - - if (in_size > TPM_BUFSIZE) - return -E2BIG; - - mutex_lock(&priv->buffer_mutex); + } if (copy_from_user (priv->data_buffer, (void __user *) buf, in_size)) { @@ -132,7 +128,7 @@ ssize_t tpm_common_write(struct file *fi return out_size; } - atomic_set(&priv->data_pending, out_size); + priv->data_pending = out_size; mutex_unlock(&priv->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ @@ -149,5 +145,5 @@ void tpm_common_release(struct file *fil del_singleshot_timer_sync(&priv->user_read_timer); flush_work(&priv->work); file->private_data = NULL; - atomic_set(&priv->data_pending, 0); + priv->data_pending = 0; } --- a/drivers/char/tpm/tpm-dev.h +++ b/drivers/char/tpm/tpm-dev.h @@ -8,7 +8,7 @@ struct file_priv { struct tpm_chip *chip; /* Data passed to and from the tpm via the read/write calls */ - atomic_t data_pending; + size_t data_pending; struct mutex buffer_mutex; struct timer_list user_read_timer; /* user needs to claim result */