summaryrefslogtreecommitdiffstats
path: root/drivers/isdn/gigaset
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2014-10-11 07:46:30 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-14 15:05:34 -0400
commitb8324f94202af7dc688576259803a2ef9a98d655 (patch)
tree05043b6668f823104c3f5eb29451a3b4f0941efd /drivers/isdn/gigaset
parent846ac30135e7c5e03b487c16c87ccb1ab020a01f (diff)
isdn/gigaset: fix non-heap pointer deallocation
at_state structures may be allocated individually or as part of a cardstate or bc_state structure. The disconnect() function handled both cases, creating a risk that it might try to deallocate an at_state structure that had not been allocated individually. Fix by splitting disconnect() into two variants handling cases with and without an associated B channel separately, and adding an explicit check. Spotted with Coverity. Signed-off-by: Tilman Schmidt <tilman@imap.cc> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn/gigaset')
-rw-r--r--drivers/isdn/gigaset/ev-layer.c111
1 files changed, 70 insertions, 41 deletions
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 0f699ebd81c5..c8ced12fa452 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -604,14 +604,14 @@ void gigaset_handle_modem_response(struct cardstate *cs)
604} 604}
605EXPORT_SYMBOL_GPL(gigaset_handle_modem_response); 605EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);
606 606
607/* disconnect 607/* disconnect_nobc
608 * process closing of connection associated with given AT state structure 608 * process closing of connection associated with given AT state structure
609 * without B channel
609 */ 610 */
610static void disconnect(struct at_state_t **at_state_p) 611static void disconnect_nobc(struct at_state_t **at_state_p,
612 struct cardstate *cs)
611{ 613{
612 unsigned long flags; 614 unsigned long flags;
613 struct bc_state *bcs = (*at_state_p)->bcs;
614 struct cardstate *cs = (*at_state_p)->cs;
615 615
616 spin_lock_irqsave(&cs->lock, flags); 616 spin_lock_irqsave(&cs->lock, flags);
617 ++(*at_state_p)->seq_index; 617 ++(*at_state_p)->seq_index;
@@ -622,23 +622,44 @@ static void disconnect(struct at_state_t **at_state_p)
622 gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE"); 622 gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE");
623 cs->commands_pending = 1; 623 cs->commands_pending = 1;
624 } 624 }
625 spin_unlock_irqrestore(&cs->lock, flags);
626 625
627 if (bcs) { 626 /* check for and deallocate temporary AT state */
628 /* B channel assigned: invoke hardware specific handler */ 627 if (!list_empty(&(*at_state_p)->list)) {
629 cs->ops->close_bchannel(bcs);
630 /* notify LL */
631 if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
632 bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
633 gigaset_isdn_hupD(bcs);
634 }
635 } else {
636 /* no B channel assigned: just deallocate */
637 spin_lock_irqsave(&cs->lock, flags);
638 list_del(&(*at_state_p)->list); 628 list_del(&(*at_state_p)->list);
639 kfree(*at_state_p); 629 kfree(*at_state_p);
640 *at_state_p = NULL; 630 *at_state_p = NULL;
641 spin_unlock_irqrestore(&cs->lock, flags); 631 }
632
633 spin_unlock_irqrestore(&cs->lock, flags);
634}
635
636/* disconnect_bc
637 * process closing of connection associated with given AT state structure
638 * and B channel
639 */
640static void disconnect_bc(struct at_state_t *at_state,
641 struct cardstate *cs, struct bc_state *bcs)
642{
643 unsigned long flags;
644
645 spin_lock_irqsave(&cs->lock, flags);
646 ++at_state->seq_index;
647
648 /* revert to selected idle mode */
649 if (!cs->cidmode) {
650 cs->at_state.pending_commands |= PC_UMMODE;
651 gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE");
652 cs->commands_pending = 1;
653 }
654 spin_unlock_irqrestore(&cs->lock, flags);
655
656 /* invoke hardware specific handler */
657 cs->ops->close_bchannel(bcs);
658
659 /* notify LL */
660 if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
661 bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
662 gigaset_isdn_hupD(bcs);
642 } 663 }
643} 664}
644 665
@@ -646,7 +667,7 @@ static void disconnect(struct at_state_t **at_state_p)
646 * get a free AT state structure: either one of those associated with the 667 * get a free AT state structure: either one of those associated with the
647 * B channels of the Gigaset device, or if none of those is available, 668 * B channels of the Gigaset device, or if none of those is available,
648 * a newly allocated one with bcs=NULL 669 * a newly allocated one with bcs=NULL
649 * The structure should be freed by calling disconnect() after use. 670 * The structure should be freed by calling disconnect_nobc() after use.
650 */ 671 */
651static inline struct at_state_t *get_free_channel(struct cardstate *cs, 672static inline struct at_state_t *get_free_channel(struct cardstate *cs,
652 int cid) 673 int cid)
@@ -1057,7 +1078,7 @@ static void do_action(int action, struct cardstate *cs,
1057 struct event_t *ev) 1078 struct event_t *ev)
1058{ 1079{
1059 struct at_state_t *at_state = *p_at_state; 1080 struct at_state_t *at_state = *p_at_state;
1060 struct at_state_t *at_state2; 1081 struct bc_state *bcs2;
1061 unsigned long flags; 1082 unsigned long flags;
1062 1083
1063 int channel; 1084 int channel;
@@ -1156,8 +1177,8 @@ static void do_action(int action, struct cardstate *cs,
1156 break; 1177 break;
1157 case ACT_RING: 1178 case ACT_RING:
1158 /* get fresh AT state structure for new CID */ 1179 /* get fresh AT state structure for new CID */
1159 at_state2 = get_free_channel(cs, ev->parameter); 1180 at_state = get_free_channel(cs, ev->parameter);
1160 if (!at_state2) { 1181 if (!at_state) {
1161 dev_warn(cs->dev, 1182 dev_warn(cs->dev,
1162 "RING ignored: could not allocate channel structure\n"); 1183 "RING ignored: could not allocate channel structure\n");
1163 break; 1184 break;
@@ -1166,16 +1187,16 @@ static void do_action(int action, struct cardstate *cs,
1166 /* initialize AT state structure 1187 /* initialize AT state structure
1167 * note that bcs may be NULL if no B channel is free 1188 * note that bcs may be NULL if no B channel is free
1168 */ 1189 */
1169 at_state2->ConState = 700; 1190 at_state->ConState = 700;
1170 for (i = 0; i < STR_NUM; ++i) { 1191 for (i = 0; i < STR_NUM; ++i) {
1171 kfree(at_state2->str_var[i]); 1192 kfree(at_state->str_var[i]);
1172 at_state2->str_var[i] = NULL; 1193 at_state->str_var[i] = NULL;
1173 } 1194 }
1174 at_state2->int_var[VAR_ZCTP] = -1; 1195 at_state->int_var[VAR_ZCTP] = -1;
1175 1196
1176 spin_lock_irqsave(&cs->lock, flags); 1197 spin_lock_irqsave(&cs->lock, flags);
1177 at_state2->timer_expires = RING_TIMEOUT; 1198 at_state->timer_expires = RING_TIMEOUT;
1178 at_state2->timer_active = 1; 1199 at_state->timer_active = 1;
1179 spin_unlock_irqrestore(&cs->lock, flags); 1200 spin_unlock_irqrestore(&cs->lock, flags);
1180 break; 1201 break;
1181 case ACT_ICALL: 1202 case ACT_ICALL:
@@ -1213,14 +1234,17 @@ static void do_action(int action, struct cardstate *cs,
1213 case ACT_DISCONNECT: 1234 case ACT_DISCONNECT:
1214 cs->cur_at_seq = SEQ_NONE; 1235 cs->cur_at_seq = SEQ_NONE;
1215 at_state->cid = -1; 1236 at_state->cid = -1;
1216 if (bcs && cs->onechannel && cs->dle) { 1237 if (!bcs) {
1238 disconnect_nobc(p_at_state, cs);
1239 } else if (cs->onechannel && cs->dle) {
1217 /* Check for other open channels not needed: 1240 /* Check for other open channels not needed:
1218 * DLE only used for M10x with one B channel. 1241 * DLE only used for M10x with one B channel.
1219 */ 1242 */
1220 at_state->pending_commands |= PC_DLE0; 1243 at_state->pending_commands |= PC_DLE0;
1221 cs->commands_pending = 1; 1244 cs->commands_pending = 1;
1222 } else 1245 } else {
1223 disconnect(p_at_state); 1246 disconnect_bc(at_state, cs, bcs);
1247 }
1224 break; 1248 break;
1225 case ACT_FAKEDLE0: 1249 case ACT_FAKEDLE0:
1226 at_state->int_var[VAR_ZDLE] = 0; 1250 at_state->int_var[VAR_ZDLE] = 0;
@@ -1228,25 +1252,27 @@ static void do_action(int action, struct cardstate *cs,
1228 /* fall through */ 1252 /* fall through */
1229 case ACT_DLE0: 1253 case ACT_DLE0:
1230 cs->cur_at_seq = SEQ_NONE; 1254 cs->cur_at_seq = SEQ_NONE;
1231 at_state2 = &cs->bcs[cs->curchannel].at_state; 1255 bcs2 = cs->bcs + cs->curchannel;
1232 disconnect(&at_state2); 1256 disconnect_bc(&bcs2->at_state, cs, bcs2);
1233 break; 1257 break;
1234 case ACT_ABORTHUP: 1258 case ACT_ABORTHUP:
1235 cs->cur_at_seq = SEQ_NONE; 1259 cs->cur_at_seq = SEQ_NONE;
1236 dev_warn(cs->dev, "Could not hang up.\n"); 1260 dev_warn(cs->dev, "Could not hang up.\n");
1237 at_state->cid = -1; 1261 at_state->cid = -1;
1238 if (bcs && cs->onechannel) 1262 if (!bcs)
1263 disconnect_nobc(p_at_state, cs);
1264 else if (cs->onechannel)
1239 at_state->pending_commands |= PC_DLE0; 1265 at_state->pending_commands |= PC_DLE0;
1240 else 1266 else
1241 disconnect(p_at_state); 1267 disconnect_bc(at_state, cs, bcs);
1242 schedule_init(cs, MS_RECOVER); 1268 schedule_init(cs, MS_RECOVER);
1243 break; 1269 break;
1244 case ACT_FAILDLE0: 1270 case ACT_FAILDLE0:
1245 cs->cur_at_seq = SEQ_NONE; 1271 cs->cur_at_seq = SEQ_NONE;
1246 dev_warn(cs->dev, "Error leaving DLE mode.\n"); 1272 dev_warn(cs->dev, "Error leaving DLE mode.\n");
1247 cs->dle = 0; 1273 cs->dle = 0;
1248 at_state2 = &cs->bcs[cs->curchannel].at_state; 1274 bcs2 = cs->bcs + cs->curchannel;
1249 disconnect(&at_state2); 1275 disconnect_bc(&bcs2->at_state, cs, bcs2);
1250 schedule_init(cs, MS_RECOVER); 1276 schedule_init(cs, MS_RECOVER);
1251 break; 1277 break;
1252 case ACT_FAILDLE1: 1278 case ACT_FAILDLE1:
@@ -1275,14 +1301,14 @@ static void do_action(int action, struct cardstate *cs,
1275 if (reinit_and_retry(cs, channel) < 0) { 1301 if (reinit_and_retry(cs, channel) < 0) {
1276 dev_warn(cs->dev, 1302 dev_warn(cs->dev,
1277 "Could not get a call ID. Cannot dial.\n"); 1303 "Could not get a call ID. Cannot dial.\n");
1278 at_state2 = &cs->bcs[channel].at_state; 1304 bcs2 = cs->bcs + channel;
1279 disconnect(&at_state2); 1305 disconnect_bc(&bcs2->at_state, cs, bcs2);
1280 } 1306 }
1281 break; 1307 break;
1282 case ACT_ABORTCID: 1308 case ACT_ABORTCID:
1283 cs->cur_at_seq = SEQ_NONE; 1309 cs->cur_at_seq = SEQ_NONE;
1284 at_state2 = &cs->bcs[cs->curchannel].at_state; 1310 bcs2 = cs->bcs + cs->curchannel;
1285 disconnect(&at_state2); 1311 disconnect_bc(&bcs2->at_state, cs, bcs2);
1286 break; 1312 break;
1287 1313
1288 case ACT_DIALING: 1314 case ACT_DIALING:
@@ -1291,7 +1317,10 @@ static void do_action(int action, struct cardstate *cs,
1291 break; 1317 break;
1292 1318
1293 case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL procssng */ 1319 case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL procssng */
1294 disconnect(p_at_state); 1320 if (bcs)
1321 disconnect_bc(at_state, cs, bcs);
1322 else
1323 disconnect_nobc(p_at_state, cs);
1295 break; 1324 break;
1296 1325
1297 case ACT_ABORTDIAL: /* error/timeout during dial preparation */ 1326 case ACT_ABORTDIAL: /* error/timeout during dial preparation */