We found a problem regarding TCP connection alias in the following code at tcp_main.c:


 int tcpconn_finish_connect( struct tcp_connection* c,

union sockaddr_union* from)

{

:

:

                                                /* remove all the aliases except the first one and re-add them

                                                * (there shouldn't be more then the 3 default aliases at this

                                                 * stage) */

                                                for (r=1; r<c->aliases; r++){

                                                                a=&c->con_aliases[r];

                                                                tcpconn_listrm(tcpconn_aliases_hash[a->hash], a, next, prev);

                                                }

                                                c->aliases=1;

 

 

As TCP_ALIAS_REPLACE flag is set for the default TCP options value, in the function _tcpconn_add_alias_unsafe() a TCP connection alias can be moved from connection A to connection B based on the TCP alias hash. In this case, the number of aliases is incremented in the connection A, and decremented from connection B. However, in the connection B the number of aliases can reach zero (no alias). And the code above can be executed for connection B setting the number of aliases to 1 unconditionally. When this case happens, the connection B keeps an invalid alias (already excluded from connection B by tcpconn_add_alias_unsafe() function called from connection A). When the connection A is released, the aliases are also released, and this memory area can be filled with different data. As connection B has references to an invalid alias it can try to access invalid areas, and can crash Kamailio. This access happens, for example, when another alias is added to connection B.

To fix it we include a check before the code:

                                                if (c->aliases>0) {

                                                                for (r=1; r<c->aliases; r++){

                                                                                a=&c->con_aliases[r];

                                                                                tcpconn_listrm(tcpconn_aliases_hash[a->hash], a, next, prev);

                                                                                memset(a,0xbb,sizeof(struct tcp_conn_alias));

                                                                }

                                                                c->aliases=1;

                                                }


Please let us know if any comments.


Thanks

Jijo