* [PATCH 1/2] tty: remove unused argument from tty_open_by_driver()
@ 2019-11-20 15:17 Sudip Mukherjee
2019-11-20 15:17 ` [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition Sudip Mukherjee
0 siblings, 1 reply; 5+ messages in thread
From: Sudip Mukherjee @ 2019-11-20 15:17 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rob Herring
Cc: linux-kernel, linux-serial, Sudip Mukherjee
The argument 'inode' passed to tty_open_by_driver() was not being used.
Remove the extra argument.
Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
---
drivers/tty/tty_io.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index a81807b394d1..cb6370906a6d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1925,7 +1925,6 @@ EXPORT_SYMBOL_GPL(tty_kopen);
/**
* tty_open_by_driver - open a tty device
* @device: dev_t of device to open
- * @inode: inode of device file
* @filp: file pointer to tty
*
* Performs the driver lookup, checks for a reopen, or otherwise
@@ -1938,7 +1937,7 @@ EXPORT_SYMBOL_GPL(tty_kopen);
* - concurrent tty driver removal w/ lookup
* - concurrent tty removal from driver table
*/
-static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
+static struct tty_struct *tty_open_by_driver(dev_t device,
struct file *filp)
{
struct tty_struct *tty;
@@ -2030,7 +2029,7 @@ static int tty_open(struct inode *inode, struct file *filp)
tty = tty_open_current_tty(device, filp);
if (!tty)
- tty = tty_open_by_driver(device, inode, filp);
+ tty = tty_open_by_driver(device, filp);
if (IS_ERR(tty)) {
tty_free_file(filp);
--
2.11.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition
2019-11-20 15:17 [PATCH 1/2] tty: remove unused argument from tty_open_by_driver() Sudip Mukherjee
@ 2019-11-20 15:17 ` Sudip Mukherjee
2019-11-20 15:44 ` Greg Kroah-Hartman
2019-11-25 6:27 ` Dan Carpenter
0 siblings, 2 replies; 5+ messages in thread
From: Sudip Mukherjee @ 2019-11-20 15:17 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rob Herring
Cc: linux-kernel, linux-serial, Sudip Mukherjee
There seems to be a race condition in tty drivers and I could see on
many boot cycles a NULL pointer dereference as tty_init_dev() tries to
do 'tty->port->itty = tty' even though tty->port is NULL.
'tty->port' will be set by the driver and if the driver has not yet done
it before we open the tty device we can get to this situation. By adding
some extra debug prints, I noticed that tty_port_link_device() is
initialising 'driver->ports[index]' just few microseconds after I
get the warning.
So, add one retry so that tty_init_dev() will return -EAGAIN on its first
try if 'tty->port' is not set yet, and then tty_open() will try to open
it again.
Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
---
drivers/tty/pty.c | 2 +-
drivers/tty/serdev/serdev-ttyport.c | 2 +-
drivers/tty/tty_io.c | 20 ++++++++++++++------
include/linux/tty.h | 3 ++-
4 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 00099a8439d2..22e8c40d9f9c 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -842,7 +842,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
mutex_lock(&tty_mutex);
- tty = tty_init_dev(ptm_driver, index);
+ tty = tty_init_dev(ptm_driver, index, 0);
/* The tty returned here is locked so we can safely
drop the mutex */
mutex_unlock(&tty_mutex);
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index d1cdd2ab8b4c..1162b4202e80 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -109,7 +109,7 @@ static int ttyport_open(struct serdev_controller *ctrl)
struct ktermios ktermios;
int ret;
- tty = tty_init_dev(serport->tty_drv, serport->tty_idx);
+ tty = tty_init_dev(serport->tty_drv, serport->tty_idx, 0);
if (IS_ERR(tty))
return PTR_ERR(tty);
serport->tty = tty;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index cb6370906a6d..e1b2086317fb 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1295,6 +1295,7 @@ static int tty_reopen(struct tty_struct *tty)
* tty_init_dev - initialise a tty device
* @driver: tty driver we are opening a device on
* @idx: device index
+ * @retry: retry count if driver has not set tty->port yet
* @ret_tty: returned tty structure
*
* Prepare a tty device. This may not be a "new" clean device but
@@ -1315,7 +1316,8 @@ static int tty_reopen(struct tty_struct *tty)
* relaxed for the (most common) case of reopening a tty.
*/
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+ int retry)
{
struct tty_struct *tty;
int retval;
@@ -1344,6 +1346,10 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
if (!tty->port)
tty->port = driver->ports[idx];
+ if (!tty->port && retry) {
+ retval = -EAGAIN;
+ goto err_release_driver;
+ }
WARN_RATELIMIT(!tty->port,
"%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
@@ -1366,6 +1372,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
/* Return the tty locked so that it cannot vanish under the caller */
return tty;
+err_release_driver:
+ tty_driver_remove_tty(driver, tty);
err_free_tty:
tty_unlock(tty);
free_tty_struct(tty);
@@ -1910,7 +1918,7 @@ struct tty_struct *tty_kopen(dev_t device)
tty_kref_put(tty);
tty = ERR_PTR(-EBUSY);
} else { /* tty_init_dev returns tty with the tty_lock held */
- tty = tty_init_dev(driver, index);
+ tty = tty_init_dev(driver, index, 0);
if (IS_ERR(tty))
goto out;
tty_port_set_kopened(tty->port, 1);
@@ -1937,7 +1945,7 @@ EXPORT_SYMBOL_GPL(tty_kopen);
* - concurrent tty driver removal w/ lookup
* - concurrent tty removal from driver table
*/
-static struct tty_struct *tty_open_by_driver(dev_t device,
+static struct tty_struct *tty_open_by_driver(dev_t device, int retry,
struct file *filp)
{
struct tty_struct *tty;
@@ -1981,7 +1989,7 @@ static struct tty_struct *tty_open_by_driver(dev_t device,
tty = ERR_PTR(retval);
}
} else { /* Returns with the tty_lock held for now */
- tty = tty_init_dev(driver, index);
+ tty = tty_init_dev(driver, index, retry);
mutex_unlock(&tty_mutex);
}
out:
@@ -2016,7 +2024,7 @@ static struct tty_struct *tty_open_by_driver(dev_t device,
static int tty_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
- int noctty, retval;
+ int noctty, retval, retry = 1;
dev_t device = inode->i_rdev;
unsigned saved_flags = filp->f_flags;
@@ -2029,7 +2037,7 @@ static int tty_open(struct inode *inode, struct file *filp)
tty = tty_open_current_tty(device, filp);
if (!tty)
- tty = tty_open_by_driver(device, filp);
+ tty = tty_open_by_driver(device, retry--, filp);
if (IS_ERR(tty)) {
tty_free_file(filp);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index bfa4e2ee94a9..2f74fc138e6a 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -559,7 +559,8 @@ extern struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx);
extern int tty_alloc_file(struct file *file);
extern void tty_add_file(struct tty_struct *tty, struct file *file);
extern void tty_free_file(struct file *file);
-extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx);
+extern struct tty_struct *tty_init_dev(struct tty_driver *driver,
+ int idx, int retry);
extern void tty_release_struct(struct tty_struct *tty, int idx);
extern int tty_release(struct inode *inode, struct file *filp);
extern void tty_init_termios(struct tty_struct *tty);
--
2.11.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition
2019-11-20 15:17 ` [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition Sudip Mukherjee
@ 2019-11-20 15:44 ` Greg Kroah-Hartman
2019-11-20 15:55 ` Sudip Mukherjee
2019-11-25 6:27 ` Dan Carpenter
1 sibling, 1 reply; 5+ messages in thread
From: Greg Kroah-Hartman @ 2019-11-20 15:44 UTC (permalink / raw)
To: Sudip Mukherjee; +Cc: Jiri Slaby, Rob Herring, linux-kernel, linux-serial
On Wed, Nov 20, 2019 at 03:17:09PM +0000, Sudip Mukherjee wrote:
> There seems to be a race condition in tty drivers and I could see on
> many boot cycles a NULL pointer dereference as tty_init_dev() tries to
> do 'tty->port->itty = tty' even though tty->port is NULL.
> 'tty->port' will be set by the driver and if the driver has not yet done
> it before we open the tty device we can get to this situation. By adding
> some extra debug prints, I noticed that tty_port_link_device() is
> initialising 'driver->ports[index]' just few microseconds after I
> get the warning.
> So, add one retry so that tty_init_dev() will return -EAGAIN on its first
> try if 'tty->port' is not set yet, and then tty_open() will try to open
> it again.
>
> Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
> ---
> drivers/tty/pty.c | 2 +-
> drivers/tty/serdev/serdev-ttyport.c | 2 +-
> drivers/tty/tty_io.c | 20 ++++++++++++++------
> include/linux/tty.h | 3 ++-
> 4 files changed, 18 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
> index 00099a8439d2..22e8c40d9f9c 100644
> --- a/drivers/tty/pty.c
> +++ b/drivers/tty/pty.c
> @@ -842,7 +842,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
>
>
> mutex_lock(&tty_mutex);
> - tty = tty_init_dev(ptm_driver, index);
> + tty = tty_init_dev(ptm_driver, index, 0);
Horrible naming scheme for this new "flag".
Look at that call here, can you instantly tell what this call is doing
with "0"? I sure can not :(
If you really want to do this, you make a different function,
tty_init_dev_retry() and then have that pass in a retry flag in the tty
core, so that any users always know what they are doing here.
But, this really feels like a race in the code somewhere:
> --- a/drivers/tty/tty_io.c
> +++ b/drivers/tty/tty_io.c
> @@ -1295,6 +1295,7 @@ static int tty_reopen(struct tty_struct *tty)
> * tty_init_dev - initialise a tty device
> * @driver: tty driver we are opening a device on
> * @idx: device index
> + * @retry: retry count if driver has not set tty->port yet
Why would tty->port not be set up already? The caller has control over
this, what is not happening correctly to cause this?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition
2019-11-20 15:44 ` Greg Kroah-Hartman
@ 2019-11-20 15:55 ` Sudip Mukherjee
0 siblings, 0 replies; 5+ messages in thread
From: Sudip Mukherjee @ 2019-11-20 15:55 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Jiri Slaby, Rob Herring, linux-kernel, linux-serial
On Wed, Nov 20, 2019 at 04:44:50PM +0100, Greg Kroah-Hartman wrote:
> On Wed, Nov 20, 2019 at 03:17:09PM +0000, Sudip Mukherjee wrote:
> > There seems to be a race condition in tty drivers and I could see on
> > many boot cycles a NULL pointer dereference as tty_init_dev() tries to
> > do 'tty->port->itty = tty' even though tty->port is NULL.
<snip>
> > +++ b/drivers/tty/pty.c
> > @@ -842,7 +842,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
> >
> >
> > mutex_lock(&tty_mutex);
> > - tty = tty_init_dev(ptm_driver, index);
> > + tty = tty_init_dev(ptm_driver, index, 0);
>
> Horrible naming scheme for this new "flag".
>
> Look at that call here, can you instantly tell what this call is doing
> with "0"? I sure can not :(
well, I also made the mistake of 1->0 in my initial patch. :(
>
> If you really want to do this, you make a different function,
> tty_init_dev_retry() and then have that pass in a retry flag in the tty
> core, so that any users always know what they are doing here.
will do.
>
> But, this really feels like a race in the code somewhere:
>
> > --- a/drivers/tty/tty_io.c
> > +++ b/drivers/tty/tty_io.c
> > @@ -1295,6 +1295,7 @@ static int tty_reopen(struct tty_struct *tty)
> > * tty_init_dev - initialise a tty device
> > * @driver: tty driver we are opening a device on
> > * @idx: device index
> > + * @retry: retry count if driver has not set tty->port yet
>
> Why would tty->port not be set up already? The caller has control over
> this, what is not happening correctly to cause this?
Will add more debugs to check what is happening now and then send you v2.
--
Regards
Sudip
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition
2019-11-20 15:17 ` [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition Sudip Mukherjee
2019-11-20 15:44 ` Greg Kroah-Hartman
@ 2019-11-25 6:27 ` Dan Carpenter
1 sibling, 0 replies; 5+ messages in thread
From: Dan Carpenter @ 2019-11-25 6:27 UTC (permalink / raw)
To: kbuild, Sudip Mukherjee
Cc: kbuild-all, Greg Kroah-Hartman, Jiri Slaby, Rob Herring,
linux-kernel, linux-serial, Sudip Mukherjee
Hi Sudip,
[auto build test WARNING on v5.4-rc8]
[cannot apply to tty/tty-testing next-20191122]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Sudip-Mukherjee/tty-remove-unused-argument-from-tty_open_by_driver/20191123-164153
base: af42d3466bdc8f39806b26f593604fdc54140bcb
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
smatch warnings:
drivers/tty/tty_io.c:1360 tty_init_dev() error: we previously assumed 'tty->port' could be null (see line 1348)
# https://github.com/0day-ci/linux/commit/8de47da07f8c6fe6f631965cafb384cd0d72ce40
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout 8de47da07f8c6fe6f631965cafb384cd0d72ce40
vim +1360 drivers/tty/tty_io.c
8de47da07f8c6f drivers/tty/tty_io.c Sudip Mukherjee 2019-11-20 1318 struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
8de47da07f8c6f drivers/tty/tty_io.c Sudip Mukherjee 2019-11-20 1319 int retry)
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1320 {
bf970ee46e0fb3 drivers/char/tty_io.c Alan Cox 2008-10-13 1321 struct tty_struct *tty;
73ec06fc5f5c8e drivers/char/tty_io.c Alan Cox 2008-10-13 1322 int retval;
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1323
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1324 /*
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1325 * First time open is complex, especially for PTY devices.
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1326 * This code guarantees that either everything succeeds and the
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1327 * TTY is ready for operation, or else the table slots are vacated
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1328 * and the allocated memory released. (Except that the termios
16b00ae82dce0e drivers/tty/tty_io.c Johan Hovold 2017-03-30 1329 * may be retained.)
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1330 */
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1331
73ec06fc5f5c8e drivers/char/tty_io.c Alan Cox 2008-10-13 1332 if (!try_module_get(driver->owner))
73ec06fc5f5c8e drivers/char/tty_io.c Alan Cox 2008-10-13 1333 return ERR_PTR(-ENODEV);
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1334
2c964a2f4191f2 drivers/tty/tty_io.c Rasmus Villemoes 2014-07-10 1335 tty = alloc_tty_struct(driver, idx);
d5543503753983 drivers/tty/tty_io.c Jiri Slaby 2011-03-23 1336 if (!tty) {
d5543503753983 drivers/tty/tty_io.c Jiri Slaby 2011-03-23 1337 retval = -ENOMEM;
d5543503753983 drivers/tty/tty_io.c Jiri Slaby 2011-03-23 1338 goto err_module_put;
d5543503753983 drivers/tty/tty_io.c Jiri Slaby 2011-03-23 1339 }
^1da177e4c3f41 drivers/char/tty_io.c Linus Torvalds 2005-04-16 1340
89c8d91e31f267 drivers/tty/tty_io.c Alan Cox 2012-08-08 1341 tty_lock(tty);
73ec06fc5f5c8e drivers/char/tty_io.c Alan Cox 2008-10-13 1342 retval = tty_driver_install_tty(driver, tty);
d5543503753983 drivers/tty/tty_io.c Jiri Slaby 2011-03-23 1343 if (retval < 0)
c8b710b3e43481 drivers/tty/tty_io.c Peter Hurley 2016-01-09 1344 goto err_free_tty;
8b0a88d5912ab5 drivers/char/tty_io.c Alan Cox 2008-10-13 1345
04831dc154df9b drivers/tty/tty_io.c Jiri Slaby 2012-06-04 1346 if (!tty->port)
04831dc154df9b drivers/tty/tty_io.c Jiri Slaby 2012-06-04 1347 tty->port = driver->ports[idx];
8de47da07f8c6f drivers/tty/tty_io.c Sudip Mukherjee 2019-11-20 @1348 if (!tty->port && retry) {
^^^^^^^^^^
Check
8de47da07f8c6f drivers/tty/tty_io.c Sudip Mukherjee 2019-11-20 1349 retval = -EAGAIN;
8de47da07f8c6f drivers/tty/tty_io.c Sudip Mukherjee 2019-11-20 1350 goto err_release_driver;
8de47da07f8c6f drivers/tty/tty_io.c Sudip Mukherjee 2019-11-20 1351 }
04831dc154df9b drivers/tty/tty_io.c Jiri Slaby 2012-06-04 1352
5d4121c04b3577 drivers/tty/tty_io.c Jiri Slaby 2012-08-17 1353 WARN_RATELIMIT(!tty->port,
5d4121c04b3577 drivers/tty/tty_io.c Jiri Slaby 2012-08-17 1354 "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
5d4121c04b3577 drivers/tty/tty_io.c Jiri Slaby 2012-08-17 1355 __func__, tty->driver->name);
5d4121c04b3577 drivers/tty/tty_io.c Jiri Slaby 2012-08-17 1356
b027e2298bd588 drivers/tty/tty_io.c Gaurav Kohli 2018-01-23 1357 retval = tty_ldisc_lock(tty, 5 * HZ);
b027e2298bd588 drivers/tty/tty_io.c Gaurav Kohli 2018-01-23 1358 if (retval)
b027e2298bd588 drivers/tty/tty_io.c Gaurav Kohli 2018-01-23 1359 goto err_release_lock;
967fab6916681e drivers/tty/tty_io.c Jiri Slaby 2012-10-18 @1360 tty->port->itty = tty;
^^^^^^^^^^^^^^^^^^^^^^
Unchecked dereference.
967fab6916681e drivers/tty/tty_io.c Jiri Slaby 2012-10-18 1361
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2019-11-25 6:29 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-20 15:17 [PATCH 1/2] tty: remove unused argument from tty_open_by_driver() Sudip Mukherjee
2019-11-20 15:17 ` [PATCH 2/2] tty: add retry to tty_init_dev() to workaround a race condition Sudip Mukherjee
2019-11-20 15:44 ` Greg Kroah-Hartman
2019-11-20 15:55 ` Sudip Mukherjee
2019-11-25 6:27 ` Dan Carpenter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).