Commit 54a6a043 authored by Anton Vasilyev's avatar Anton Vasilyev Committed by David S. Miller

mISDN: Fix null pointer dereference at mISDN_FsmNew

If mISDN_FsmNew() fails to allocate memory for jumpmatrix
then null pointer dereference will occur on any write to
jumpmatrix.

The patch adds check on successful allocation and
corresponding error handling.

Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: default avatarAnton Vasilyev <vasilyev@ispras.ru>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bb3afda4
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#define FSM_TIMER_DEBUG 0 #define FSM_TIMER_DEBUG 0
void int
mISDN_FsmNew(struct Fsm *fsm, mISDN_FsmNew(struct Fsm *fsm,
struct FsmNode *fnlist, int fncount) struct FsmNode *fnlist, int fncount)
{ {
...@@ -34,6 +34,8 @@ mISDN_FsmNew(struct Fsm *fsm, ...@@ -34,6 +34,8 @@ mISDN_FsmNew(struct Fsm *fsm,
fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count * fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count *
fsm->event_count, GFP_KERNEL); fsm->event_count, GFP_KERNEL);
if (fsm->jumpmatrix == NULL)
return -ENOMEM;
for (i = 0; i < fncount; i++) for (i = 0; i < fncount; i++)
if ((fnlist[i].state >= fsm->state_count) || if ((fnlist[i].state >= fsm->state_count) ||
...@@ -45,6 +47,7 @@ mISDN_FsmNew(struct Fsm *fsm, ...@@ -45,6 +47,7 @@ mISDN_FsmNew(struct Fsm *fsm,
} else } else
fsm->jumpmatrix[fsm->state_count * fnlist[i].event + fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
return 0;
} }
EXPORT_SYMBOL(mISDN_FsmNew); EXPORT_SYMBOL(mISDN_FsmNew);
......
...@@ -55,7 +55,7 @@ struct FsmTimer { ...@@ -55,7 +55,7 @@ struct FsmTimer {
void *arg; void *arg;
}; };
extern void mISDN_FsmNew(struct Fsm *, struct FsmNode *, int); extern int mISDN_FsmNew(struct Fsm *, struct FsmNode *, int);
extern void mISDN_FsmFree(struct Fsm *); extern void mISDN_FsmFree(struct Fsm *);
extern int mISDN_FsmEvent(struct FsmInst *, int , void *); extern int mISDN_FsmEvent(struct FsmInst *, int , void *);
extern void mISDN_FsmChangeState(struct FsmInst *, int); extern void mISDN_FsmChangeState(struct FsmInst *, int);
......
...@@ -414,8 +414,7 @@ l1_init(u_int *deb) ...@@ -414,8 +414,7 @@ l1_init(u_int *deb)
l1fsm_s.event_count = L1_EVENT_COUNT; l1fsm_s.event_count = L1_EVENT_COUNT;
l1fsm_s.strEvent = strL1Event; l1fsm_s.strEvent = strL1Event;
l1fsm_s.strState = strL1SState; l1fsm_s.strState = strL1SState;
mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); return mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList));
return 0;
} }
void void
......
...@@ -2247,15 +2247,26 @@ static struct Bprotocol X75SLP = { ...@@ -2247,15 +2247,26 @@ static struct Bprotocol X75SLP = {
int int
Isdnl2_Init(u_int *deb) Isdnl2_Init(u_int *deb)
{ {
int res;
debug = deb; debug = deb;
mISDN_register_Bprotocol(&X75SLP); mISDN_register_Bprotocol(&X75SLP);
l2fsm.state_count = L2_STATE_COUNT; l2fsm.state_count = L2_STATE_COUNT;
l2fsm.event_count = L2_EVENT_COUNT; l2fsm.event_count = L2_EVENT_COUNT;
l2fsm.strEvent = strL2Event; l2fsm.strEvent = strL2Event;
l2fsm.strState = strL2State; l2fsm.strState = strL2State;
mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); res = mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
TEIInit(deb); if (res)
goto error;
res = TEIInit(deb);
if (res)
goto error_fsm;
return 0; return 0;
error_fsm:
mISDN_FsmFree(&l2fsm);
error:
mISDN_unregister_Bprotocol(&X75SLP);
return res;
} }
void void
......
...@@ -1387,23 +1387,37 @@ create_teimanager(struct mISDNdevice *dev) ...@@ -1387,23 +1387,37 @@ create_teimanager(struct mISDNdevice *dev)
int TEIInit(u_int *deb) int TEIInit(u_int *deb)
{ {
int res;
debug = deb; debug = deb;
teifsmu.state_count = TEI_STATE_COUNT; teifsmu.state_count = TEI_STATE_COUNT;
teifsmu.event_count = TEI_EVENT_COUNT; teifsmu.event_count = TEI_EVENT_COUNT;
teifsmu.strEvent = strTeiEvent; teifsmu.strEvent = strTeiEvent;
teifsmu.strState = strTeiState; teifsmu.strState = strTeiState;
mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); res = mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser));
if (res)
goto error;
teifsmn.state_count = TEI_STATE_COUNT; teifsmn.state_count = TEI_STATE_COUNT;
teifsmn.event_count = TEI_EVENT_COUNT; teifsmn.event_count = TEI_EVENT_COUNT;
teifsmn.strEvent = strTeiEvent; teifsmn.strEvent = strTeiEvent;
teifsmn.strState = strTeiState; teifsmn.strState = strTeiState;
mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); res = mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet));
if (res)
goto error_smn;
deactfsm.state_count = DEACT_STATE_COUNT; deactfsm.state_count = DEACT_STATE_COUNT;
deactfsm.event_count = DEACT_EVENT_COUNT; deactfsm.event_count = DEACT_EVENT_COUNT;
deactfsm.strEvent = strDeactEvent; deactfsm.strEvent = strDeactEvent;
deactfsm.strState = strDeactState; deactfsm.strState = strDeactState;
mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); res = mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList));
if (res)
goto error_deact;
return 0; return 0;
error_deact:
mISDN_FsmFree(&teifsmn);
error_smn:
mISDN_FsmFree(&teifsmu);
error:
return res;
} }
void TEIFree(void) void TEIFree(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment