res_fax: fix segfault on inactive "reserved" fax session
authorAlexei Gradinari <alex2grad@gmail.com>
Tue, 28 May 2019 20:35:17 +0000 (16:35 -0400)
committerGeorge Joseph <gjoseph@digium.com>
Mon, 3 Jun 2019 13:30:27 +0000 (07:30 -0600)
The change #10017 "Handle fax gateway being started more than once"
introdiced a bug which leads to segfault in res_fax_spandsp.

The res_fax_spandsp module does not support reserving sessions, so
fax_session_reserve returns a fax session with state AST_FAX_STATE_INACTIVE.

The fax_gateway_start does not create a real fax session if the fax session
is already present and the state is not AST_FAX_STATE_RESERVED.
But the "reserved" session created for res_fax_spandsp has state
AST_FAX_STATE_INACTIVE, so fax_gateway_start not starting.

Then when fax_gateway_framehook is called and gateway T.38 state is
NEGOTIATED the call of gateway->s->tech->write(gateway->s, f) leads to
segfault, because session tech_pvt is not set, i.e. the tech session
was not initialized/started.

This patch adds check also on AST_FAX_STATE_INACTIVE to the "reserved"
session created for res_fax_spandsp will start.

This patch also adds extra check and log ERROR if tech_pvt is not set
before call tech->write.

ASTERISK-27981 #close

Change-Id: Ife3e65e5f18c902db2ff0538fccf7d28f88fa803

res/res_fax.c

index 7338507..647ec2a 100644 (file)
@@ -1106,6 +1106,7 @@ static void destroy_session(void *session)
                        s->details->caps &= ~AST_FAX_TECH_GATEWAY;
                }
                ao2_ref(s->details, -1);
+               s->details = NULL;
        }
 
        if (s->debug_info) {
@@ -2915,7 +2916,8 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session
        int start_res;
 
        /* if the fax gateway is already started then do nothing */
-       if (gateway->s && gateway->s->state != AST_FAX_STATE_RESERVED) {
+       if (gateway->s &&
+               gateway->s->state != AST_FAX_STATE_RESERVED && gateway->s->state != AST_FAX_STATE_INACTIVE) {
                return 0;
        }
 
@@ -3510,6 +3512,12 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct
        /* in gateway mode, gateway some packets */
        if (gateway->t38_state == T38_STATE_NEGOTIATED) {
                struct ast_trans_pvt *readtrans;
+
+               if (!gateway->s || !gateway->s->tech_pvt) {
+                       ast_log(LOG_ERROR, "no FAX session on chan %s for T.38 gateway session, odd", ast_channel_name(chan));
+                       return f;
+               }
+
                /* framehooks are called in __ast_read() before frame format
                 * translation is done, so we need to translate here */
                if ((f->frametype == AST_FRAME_VOICE) && (ast_format_cmp(f->subclass.format, ast_format_slin) != AST_FORMAT_CMP_EQUAL)