diff --git a/src/amf/amf-sm.c b/src/amf/amf-sm.c index b62b5e7b1..ca1f9c93a 100644 --- a/src/amf/amf-sm.c +++ b/src/amf/amf-sm.c @@ -597,15 +597,35 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; } diff --git a/src/ausf/ausf-sm.c b/src/ausf/ausf-sm.c index a7104997b..899a09dff 100644 --- a/src/ausf/ausf-sm.c +++ b/src/ausf/ausf-sm.c @@ -358,15 +358,35 @@ void ausf_state_operational(ogs_fsm_t *s, ausf_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; } diff --git a/src/bsf/bsf-sm.c b/src/bsf/bsf-sm.c index bba9e7558..ae13cd18e 100644 --- a/src/bsf/bsf-sm.c +++ b/src/bsf/bsf-sm.c @@ -342,15 +342,35 @@ void bsf_state_operational(ogs_fsm_t *s, bsf_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; } diff --git a/src/pcf/pcf-sm.c b/src/pcf/pcf-sm.c index 3393622e9..e4e8adcf3 100644 --- a/src/pcf/pcf-sm.c +++ b/src/pcf/pcf-sm.c @@ -588,15 +588,35 @@ void pcf_state_operational(ogs_fsm_t *s, pcf_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; } diff --git a/src/scp/scp-sm.c b/src/scp/scp-sm.c index 1ac121664..d6c227cfb 100644 --- a/src/scp/scp-sm.c +++ b/src/scp/scp-sm.c @@ -244,15 +244,35 @@ void scp_state_operational(ogs_fsm_t *s, scp_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; } diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c index 0980cbc9b..bb5d877c9 100644 --- a/src/smf/smf-sm.c +++ b/src/smf/smf-sm.c @@ -832,15 +832,35 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; } diff --git a/src/udm/udm-sm.c b/src/udm/udm-sm.c index 25c03b6d0..424803304 100644 --- a/src/udm/udm-sm.c +++ b/src/udm/udm-sm.c @@ -399,15 +399,35 @@ void udm_state_operational(ogs_fsm_t *s, udm_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; } diff --git a/tests/af/af-sm.c b/tests/af/af-sm.c index 18780a91b..95de0941a 100644 --- a/tests/af/af-sm.c +++ b/tests/af/af-sm.c @@ -427,15 +427,35 @@ void af_state_operational(ogs_fsm_t *s, af_event_t *e) break; case OGS_TIMER_SBI_CLIENT_WAIT: - sbi_xact = e->h.sbi.data; - ogs_assert(sbi_xact); - - sbi_xact = ogs_sbi_xact_cycle(sbi_xact); + /* + * ogs_pollset_poll() receives the time of the expiration + * of next timer as an argument. If this timeout is + * in very near future (1 millisecond), and if there are + * multiple events that need to be processed by ogs_pollset_poll(), + * these could take more than 1 millisecond for processing, + * resulting in the timer already passed the expiration. + * + * In case that another NF is under heavy load and responds + * to an SBI request with some delay of a few seconds, + * it can happen that ogs_pollset_poll() adds SBI responses + * to the event list for further processing, + * then ogs_timer_mgr_expire() is called which will add + * an additional event for timer expiration. When all events are + * processed one-by-one, the SBI xact would get deleted twice + * in a row, resulting in a crash. + * + * 1. ogs_pollset_poll() + * message was received and put into an event list, + * 2. ogs_timer_mgr_expire() + * add an additional event for timer expiration + * 3. message event is processed. (free SBI xact) + * 4. timer expiration event is processed. (double-free SBI xact) + * + * To avoid double-free SBI xact, + * we need to check ogs_sbi_xact_cycle() + */ + sbi_xact = ogs_sbi_xact_cycle(e->h.sbi.data); if (!sbi_xact) { - /* message was received and put into an event list, - * but not yet processed before timer expiration event - * was put into event list - */ ogs_error("SBI transaction has already been removed"); break; }