Skip to content

Commit b696346

Browse files
committed
tty: n_gsm: fix restart handling via CLD command
jira VULN-676 cve-pre CVE-2023-6546 commit-author Daniel Starke <daniel.starke@siemens.com> commit aa371e9 n_gsm is based on the 3GPP 07.010 and its newer version is the 3GPP 27.010. See https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1516 The changes from 07.010 to 27.010 are non-functional. Therefore, I refer to the newer 27.010 here. Chapter 5.8.2 states that both sides will revert to the non-multiplexed mode via a close-down message (CLD). The usual program flow is as following: - start multiplex mode by sending AT+CMUX to the mobile - establish the control channel (DLCI 0) - establish user channels (DLCI >0) - terminate user channels - send close-down message (CLD) - revert to AT protocol (i.e. leave multiplexed mode) The AT protocol is out of scope of the n_gsm driver. However, gsm_disconnect() sends CLD if gsm_config() detects that the requested parameters require the mux protocol to restart. The next immediate action is to start the mux protocol by opening DLCI 0 again. Any responder side which handles CLD commands correctly forces us to fail at this point because AT+CMUX needs to be sent to the mobile to start the mux again. Therefore, remove the CLD command in this phase and keep both sides in multiplexed mode. Remove the gsm_disconnect() function as it become unnecessary and merge the remaining parts into gsm_cleanup_mux() to handle the termination order and locking correctly. Fixes: 71e0779 ("tty: n_gsm: do not send/receive in ldisc close path") Cc: stable@vger.kernel.org Signed-off-by: Daniel Starke <daniel.starke@siemens.com> Link: https://lore.kernel.org/r/20220414094225.4527-2-daniel.starke@siemens.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit aa371e9) Signed-off-by: David Gomez <dgomez@ciq.com>
1 parent ebf5f96 commit b696346

File tree

1 file changed

+20
-48
lines changed

1 file changed

+20
-48
lines changed

drivers/tty/n_gsm.c

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,49 +2037,35 @@ static void gsm_error(struct gsm_mux *gsm,
20372037
gsm->io_error++;
20382038
}
20392039

2040-
static int gsm_disconnect(struct gsm_mux *gsm)
2041-
{
2042-
struct gsm_dlci *dlci = gsm->dlci[0];
2043-
struct gsm_control *gc;
2044-
2045-
if (!dlci)
2046-
return 0;
2047-
2048-
/* In theory disconnecting DLCI 0 is sufficient but for some
2049-
modems this is apparently not the case. */
2050-
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
2051-
if (gc)
2052-
gsm_control_wait(gsm, gc);
2053-
2054-
del_timer_sync(&gsm->t2_timer);
2055-
/* Now we are sure T2 has stopped */
2056-
2057-
gsm_dlci_begin_close(dlci);
2058-
wait_event_interruptible(gsm->event,
2059-
dlci->state == DLCI_CLOSED);
2060-
2061-
if (signal_pending(current))
2062-
return -EINTR;
2063-
2064-
return 0;
2065-
}
2066-
20672040
/**
20682041
* gsm_cleanup_mux - generic GSM protocol cleanup
20692042
* @gsm: our mux
2043+
* @disc: disconnect link?
20702044
*
20712045
* Clean up the bits of the mux which are the same for all framing
20722046
* protocols. Remove the mux from the mux table, stop all the timers
20732047
* and then shut down each device hanging up the channels as we go.
20742048
*/
20752049

2076-
static void gsm_cleanup_mux(struct gsm_mux *gsm)
2050+
static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
20772051
{
20782052
int i;
20792053
struct gsm_dlci *dlci = gsm->dlci[0];
20802054
struct gsm_msg *txq, *ntxq;
20812055

20822056
gsm->dead = true;
2057+
mutex_lock(&gsm->mutex);
2058+
2059+
if (dlci) {
2060+
if (disc && dlci->state != DLCI_CLOSED) {
2061+
gsm_dlci_begin_close(dlci);
2062+
wait_event(gsm->event, dlci->state == DLCI_CLOSED);
2063+
}
2064+
dlci->dead = true;
2065+
}
2066+
2067+
/* Finish outstanding timers, making sure they are done */
2068+
del_timer_sync(&gsm->t2_timer);
20832069

20842070
spin_lock(&gsm_mux_lock);
20852071
for (i = 0; i < MAX_MUX; i++) {
@@ -2093,13 +2079,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
20932079
if (i == MAX_MUX)
20942080
return;
20952081

2096-
del_timer_sync(&gsm->t2_timer);
2097-
/* Now we are sure T2 has stopped */
2098-
if (dlci)
2099-
dlci->dead = true;
2100-
21012082
/* Free up any link layer users */
2102-
mutex_lock(&gsm->mutex);
21032083
for (i = 0; i < NUM_DLCI; i++)
21042084
if (gsm->dlci[i])
21052085
gsm_dlci_release(gsm->dlci[i]);
@@ -2301,19 +2281,11 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
23012281

23022282
/*
23032283
* Close down what is needed, restart and initiate the new
2304-
* configuration
2284+
* configuration. On the first time there is no DLCI[0]
2285+
* and closing or cleaning up is not necessary.
23052286
*/
2306-
2307-
if (need_close || need_restart) {
2308-
int ret;
2309-
2310-
ret = gsm_disconnect(gsm);
2311-
2312-
if (ret)
2313-
return ret;
2314-
}
2315-
if (need_restart)
2316-
gsm_cleanup_mux(gsm);
2287+
if (need_close || need_restart)
2288+
gsm_cleanup_mux(gsm, true);
23172289

23182290
gsm->initiator = c->initiator;
23192291
gsm->mru = c->mru;
@@ -2426,7 +2398,7 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
24262398
for (i = 1; i < NUM_DLCI; i++)
24272399
tty_unregister_device(gsm_tty_driver, base + i);
24282400
}
2429-
gsm_cleanup_mux(gsm);
2401+
gsm_cleanup_mux(gsm, false);
24302402
tty_kref_put(gsm->tty);
24312403
gsm->tty = NULL;
24322404
}
@@ -2529,7 +2501,7 @@ static int gsmld_open(struct tty_struct *tty)
25292501

25302502
ret = gsmld_attach_gsm(tty, gsm);
25312503
if (ret != 0) {
2532-
gsm_cleanup_mux(gsm);
2504+
gsm_cleanup_mux(gsm, false);
25332505
mux_put(gsm);
25342506
}
25352507
return ret;

0 commit comments

Comments
 (0)