From: yangerkun <yangerkun(a)huawei.com>
commit f596c87005f7b1baeb7d62d9a9e25d68c3dfae10 upstream.
As the description before netdev_run_todo, we cannot call free_netdev
before rtnl_unlock, fix it by reorder the code.
Signed-off-by: yangerkun <yangerkun(a)huawei.com>
Reviewed-by: Oliver Hartkopp <socketcan(a)hartkopp.net>
Signed-off-by: David S. Miller <davem(a)davemloft.net>
[bwh: Backported to <4.11: free_netdev() is called through sl_free_netdev()]
Signed-off-by: Ben Hutchings <ben(a)decadent.org.uk>
---
drivers/net/slip/slip.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index cc841126147e..f870396e05e1 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -867,7 +867,10 @@ static int slip_open(struct tty_struct *tty)
sl->tty = NULL;
tty->disc_data = NULL;
clear_bit(SLF_INUSE, &sl->flags);
+ /* do not call free_netdev before rtnl_unlock */
+ rtnl_unlock();
sl_free_netdev(sl->dev);
+ return err;
err_exit:
rtnl_unlock();
Commit 9ebd796e2400 ("can: slcan: Fix use-after-free Read in
slcan_open") was incorrectly backported to 4.4 and 4.9 stable
branches.
Since they do not have commit cf124db566e6 ("net: Fix inconsistent
teardown and release of private netdev state."), the destructor
function slc_free_netdev() is already responsible for calling
free_netdev() and slcan_open() must not call both of them.
yangerkun previously fixed the same bug in slip.
Fixes: ce624b2089ea ("can: slcan: Fix use-after-free Read in slcan_open") # 4.4
Fixes: f59604a80fa4 ("slcan: not call free_netdev before rtnl_unlock ...") # 4.4
Fixes: 56635a1e6ffb ("can: slcan: Fix use-after-free Read in slcan_open") # 4.9
Fixes: a1c9b23142ac ("slcan: not call free_netdev before rtnl_unlock ...") # 4.9
Cc: yangerkun <yangerkun(a)huawei.com>
Signed-off-by: Ben Hutchings <ben(a)decadent.org.uk>
---
drivers/net/can/slcan.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index d0435c7631ff..9c938f9892b2 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -618,10 +618,9 @@ static int slcan_open(struct tty_struct *tty)
sl->tty = NULL;
tty->disc_data = NULL;
clear_bit(SLF_INUSE, &sl->flags);
- slc_free_netdev(sl->dev);
/* do not call free_netdev before rtnl_unlock */
rtnl_unlock();
- free_netdev(sl->dev);
+ slc_free_netdev(sl->dev);
return err;
err_exit:
From: James Bottomley <James.Bottomley(a)HansenPartnership.com>
BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1881710
It has been reported that some TIS based TPMs are giving unexpected
errors when using the O_NONBLOCK path of the TPM device. The problem
is that some TPMs don't like it when you get and then relinquish a
locality (as the tpm_try_get_ops()/tpm_put_ops() pair does) without
sending a command. This currently happens all the time in the
O_NONBLOCK write path. Fix this by moving the tpm_try_get_ops()
further down the code to after the O_NONBLOCK determination is made.
This is safe because the priv->buffer_mutex still protects the priv
state being modified.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206275
Fixes: d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode")
Reported-by: Mario Limonciello <Mario.Limonciello(a)dell.com>
Tested-by: Alex Guzman <alex(a)guzman.io>
Cc: stable(a)vger.kernel.org
Reviewed-by: Jerry Snitselaar <jsnitsel(a)redhat.com>
Signed-off-by: James Bottomley <James.Bottomley(a)HansenPartnership.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen(a)linux.intel.com>
(cherry picked from https://patchwork.kernel.org/patch/11576453/)
Signed-off-by: Ivan Hu <ivan.hu(a)canonical.com>
---
drivers/char/tpm/tpm-dev-common.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
index 87f449340202..1784530b8387 100644
--- a/drivers/char/tpm/tpm-dev-common.c
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -189,15 +189,6 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
goto out;
}
- /* atomic tpm command send and result receive. We only hold the ops
- * lock during this period so that the tpm can be unregistered even if
- * the char dev is held open.
- */
- if (tpm_try_get_ops(priv->chip)) {
- ret = -EPIPE;
- goto out;
- }
-
priv->response_length = 0;
priv->response_read = false;
*off = 0;
@@ -211,11 +202,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
if (file->f_flags & O_NONBLOCK) {
priv->command_enqueued = true;
queue_work(tpm_dev_wq, &priv->async_work);
- tpm_put_ops(priv->chip);
mutex_unlock(&priv->buffer_mutex);
return size;
}
+ /* atomic tpm command send and result receive. We only hold the ops
+ * lock during this period so that the tpm can be unregistered even if
+ * the char dev is held open.
+ */
+ if (tpm_try_get_ops(priv->chip)) {
+ ret = -EPIPE;
+ goto out;
+ }
+
ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer));
tpm_put_ops(priv->chip);
--
2.17.1
From: James Bottomley <James.Bottomley(a)HansenPartnership.com>
BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1881710
It has been reported that some TIS based TPMs are giving unexpected
errors when using the O_NONBLOCK path of the TPM device. The problem
is that some TPMs don't like it when you get and then relinquish a
locality (as the tpm_try_get_ops()/tpm_put_ops() pair does) without
sending a command. This currently happens all the time in the
O_NONBLOCK write path. Fix this by moving the tpm_try_get_ops()
further down the code to after the O_NONBLOCK determination is made.
This is safe because the priv->buffer_mutex still protects the priv
state being modified.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206275
Fixes: d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode")
Reported-by: Mario Limonciello <Mario.Limonciello(a)dell.com>
Tested-by: Alex Guzman <alex(a)guzman.io>
Cc: stable(a)vger.kernel.org
Reviewed-by: Jerry Snitselaar <jsnitsel(a)redhat.com>
Signed-off-by: James Bottomley <James.Bottomley(a)HansenPartnership.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen(a)linux.intel.com>
(backported from https://patchwork.kernel.org/patch/11576453/)
Signed-off-by: Ivan Hu <ivan.hu(a)canonical.com>
---
drivers/char/tpm/tpm-dev-common.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
index 10b9f63701e6..de55205d3a11 100644
--- a/drivers/char/tpm/tpm-dev-common.c
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -164,15 +164,6 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
goto out;
}
- /* atomic tpm command send and result receive. We only hold the ops
- * lock during this period so that the tpm can be unregistered even if
- * the char dev is held open.
- */
- if (tpm_try_get_ops(priv->chip)) {
- ret = -EPIPE;
- goto out;
- }
-
priv->response_length = 0;
priv->response_read = false;
*off = 0;
@@ -186,11 +177,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
if (file->f_flags & O_NONBLOCK) {
priv->command_enqueued = true;
queue_work(tpm_dev_wq, &priv->async_work);
- tpm_put_ops(priv->chip);
mutex_unlock(&priv->buffer_mutex);
return size;
}
+ /* atomic tpm command send and result receive. We only hold the ops
+ * lock during this period so that the tpm can be unregistered even if
+ * the char dev is held open.
+ */
+ if (tpm_try_get_ops(priv->chip)) {
+ ret = -EPIPE;
+ goto out;
+ }
+
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer), 0);
tpm_put_ops(priv->chip);
--
2.17.1