FAILED: patch "[PATCH] tpm: fix race condition in tpm_common_write()" failed to apply to 4.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
3ab2011ea368ec3433ad49e1b9e1c7b70d2e65dfMon Sep 17 00:00:00 2001
From: Tadeusz Struk <[email protected]>
Date: Tue, 22 May 2018 14:37:18 -0700
Subject: [PATCH] tpm: fix race condition in tpm_common_write()
There is a race condition in tpm_common_write function allowing two threads on the same /dev/tpm<N>, or two different applications on the same /dev/tpmrm<N> 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.
drivers/char/tpm/tpm-dev-common.c +18 -22
@@ -37,7 +37,7 @@ static void timeout_work(struct work_struct *work) 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 tpm_chip *chip, 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 *file, char __user *buf, 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 *file, const char __user *buf,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 *file, const char __user *buf,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 *file, struct file_priv *priv)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 ; }
drivers/char/tpm/tpm-dev.h +1 -1
@@ -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 */
Sudip Mukherjee
Reviewed-by Jarkko SakkinenHi Greg,
Quoted 5 lines · On Sun, Jul 01, 2018 at 11:34:24AM +0200, [email protected] wrote:
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
The attached backported patch should apply to 4.4-stable tree. It will also apply to 4.9-stable.
It did not apply originally as patch was looking for the splitted files. The split was done by:ecb38e2f521b ("tpm: split out tpm-dev.c into tpm-dev.c and tpm-common-dev.c")
--
Regards
Sudip
Quoted 1 line
From
a8298614c8686b8c9e8706d79a63634cde4684e4Mon Sep 17 00:00:00 2001
From: Tadeusz Struk <[email protected]>
Date: Tue, 22 May 2018 14:37:18 -0700
Subject: [PATCH] tpm: fix race condition in tpm_common_write()
commit 3ab2011ea368ec3433ad49e1b9e1c7b70d2e65df upstream
There is a race condition in tpm_common_write function allowing two threads on the same /dev/tpm<N>, or two different applications on the same /dev/tpmrm<N> 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.
--- drivers/char/tpm/tpm-dev.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-)
drivers/char/tpm/tpm-dev.c +19 -22
@@ -25,7 +25,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 */
@@ -46,7 +46,7 @@ static void timeout_work(struct work_struct *work) 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); }
@@ -72,7 +72,6 @@ static int tpm_open(struct inode *inode, struct file *file) } priv->chip = chip; -atomic_set (&priv->data_pending,0 );mutex_init (&priv->buffer_mutex);setup_timer (&priv->user_read_timer, user_reader_timeout, (unsigned long )priv);
@@ -86,28 +85,24 @@ static ssize_t tpm_read(struct file *file, char __user *buf, size_t size, loff_t *off) { struct file_priv *priv = file->private_data; -ssize_t 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 */ -ssize_t 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; }
@@ -118,17 +113,19 @@ static ssize_t tpm_write(struct file *file, const char __user *buf,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 splitted 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)) {
@@ -153,7 +150,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf,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 */
@@ -172,7 +169,7 @@ static int tpm_release(struct inode *inode, struct file *file)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 ;clear_bit (0 , &priv->chip->is_open);kfree (priv);return 0 ;
Signature · 1 line
2.11.0
Greg KH
maintainerQuoted 42 lines · Sudip Mukherjee
Hi Greg,
Quoted 5 lines · On Sun, Jul 01, 2018 at 11:34:24AM +0200, [email protected] wrote:
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.The attached backported patch should apply to 4.4-stable tree. It will also apply to 4.9-stable.
It did not apply originally as patch was looking for the splitted files. The split was done by:
ecb38e2f521b("tpm: split outtpm-dev.cintotpm-dev.candtpm-common-dev.c")--
Regards
SudipQuoted 1 line
From
a8298614c8686b8c9e8706d79a63634cde4684e4Mon Sep 17 00:00:00 2001From: Tadeusz Struk <[email protected]>
Date: Tue, 22 May 2018 14:37:18 -0700
Subject: [PATCH] tpm: fix race condition intpm_common_write()commit
3ab2011ea368ec3433ad49e1b9e1c7b70d2e65dfupstreamThere is a race condition in
tpm_common_writefunction allowing two threads on the same /dev/tpm<N>, or two different applications on the same /dev/tpmrm<N> to overwrite each other commands/responses. Fixed this by taking thepriv->buffer_mutexearly in the function.Also converted the
priv->data_pendingfrom atomic to a regularsize_ttype. There is no need for it to be atomic since it is only touched under the protection of thepriv->buffer_mutex.Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")Signed-off-by Tadeusz Struk <[email protected]>Reviewed-by Jarkko Sakkinen <[email protected]>Signed-off-by Jarkko Sakkinen <[email protected]>Signed-off-by Sudip Mukherjee <[email protected]>
Quoted 3 lines
--- drivers/char/tpm/tpm-dev.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-)
Sorry, but someone already backported this before you did.
thanks,
greg k-h