aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPan Xinhui <xinhuix.pan@intel.com>2015-03-27 22:42:56 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-05-10 13:25:32 -0400
commit8f9cfeed3eae86c70d3b04445a6f2036b27b6304 (patch)
tree2582a9a80a8961dc8f0598570c77bc871f05598e
parentec61847855094d6f6144340b26f14203f25dd4e9 (diff)
tty/n_gsm.c: fix a memory leak when gsmtty is removed
when gsmtty_remove put dlci, it will cause memory leak if dlci->port's refcount is zero. So we do the cleanup work in .cleanup callback instead. dlci will be last put in two call chains. 1) gsmld_close -> gsm_cleanup_mux -> gsm_dlci_release -> dlci_put 2) gsmld_remove -> dlci_put so there is a race. the memory leak depends on the race. In call chain 2. we hit the memory leak. below comment tells. release_tty -> tty_driver_remove_tty -> gsmtty_remove -> dlci_put -> tty_port_destructor (WARN_ON(port->itty) and return directly) | tty->port->itty = NULL; | tty_kref_put ---> release_one_tty -> gsmtty_cleanup (added by our patch) So our patch fix the memory leak by doing the cleanup work after tty core did. Signed-off-by: Pan Xinhui <xinhuix.pan@intel.com> Fixes: dfabf7ffa30585 Cc: stable <stable@vger.kernel.org> # 3.14+ Acked-by: Jiri Slaby <jslaby@suse.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/n_gsm.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 91abc00aa833..2c34c3249972 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -3170,7 +3170,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
3170 return gsmtty_modem_update(dlci, encode); 3170 return gsmtty_modem_update(dlci, encode);
3171} 3171}
3172 3172
3173static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) 3173static void gsmtty_cleanup(struct tty_struct *tty)
3174{ 3174{
3175 struct gsm_dlci *dlci = tty->driver_data; 3175 struct gsm_dlci *dlci = tty->driver_data;
3176 struct gsm_mux *gsm = dlci->gsm; 3176 struct gsm_mux *gsm = dlci->gsm;
@@ -3178,7 +3178,6 @@ static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty)
3178 dlci_put(dlci); 3178 dlci_put(dlci);
3179 dlci_put(gsm->dlci[0]); 3179 dlci_put(gsm->dlci[0]);
3180 mux_put(gsm); 3180 mux_put(gsm);
3181 driver->ttys[tty->index] = NULL;
3182} 3181}
3183 3182
3184/* Virtual ttys for the demux */ 3183/* Virtual ttys for the demux */
@@ -3199,7 +3198,7 @@ static const struct tty_operations gsmtty_ops = {
3199 .tiocmget = gsmtty_tiocmget, 3198 .tiocmget = gsmtty_tiocmget,
3200 .tiocmset = gsmtty_tiocmset, 3199 .tiocmset = gsmtty_tiocmset,
3201 .break_ctl = gsmtty_break_ctl, 3200 .break_ctl = gsmtty_break_ctl,
3202 .remove = gsmtty_remove, 3201 .cleanup = gsmtty_cleanup,
3203}; 3202};
3204 3203
3205 3204