res_rtp_asterisk.c: Check DTLS packets against ICE candidate list

When ICE is in use, we can prevent a possible DOS attack by allowing
DTLS protocol messages (client hello, etc) only from sources that
are in the active remote candidates list.

Resolves: GHSA-hxj9-xwr8-w8pq
This commit is contained in:
George Joseph 2023-11-09 09:14:03 -07:00
parent ce4f512bb7
commit 00921cecda
1 changed files with 55 additions and 0 deletions

View File

@ -3207,6 +3207,61 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
ast_debug_dtls(3, "(%p) DTLS - __rtp_recvfrom rtp=%p - Got SSL packet '%d'\n", instance, rtp, *in);
/*
* If ICE is in use, we can prevent a possible DOS attack
* by allowing DTLS protocol messages (client hello, etc)
* only from sources that are in the active remote
* candidates list.
*/
if (rtp->ice) {
int pass_src_check = 0;
struct ao2_iterator i;
struct ast_rtp_engine_ice_candidate *candidate;
int cand_cnt = 0;
/*
* You'd think that this check would cause a "deadlock"
* because ast_rtp_ice_start_media calls dtls_perform_handshake
* before it sets ice_media_started = 1 so how can we do a
* handshake if we're dropping packets before we send them
* to openssl. Fortunately, dtls_perform_handshake just sets
* up openssl to do the handshake and doesn't actually perform it
* itself and the locking prevents __rtp_recvfrom from
* running before the ice_media_started flag is set. So only
* unexpected DTLS packets can get dropped here.
*/
if (!rtp->ice_media_started) {
ast_log(LOG_WARNING, "%s: DTLS packet from %s dropped. ICE not completed yet.\n",
ast_rtp_instance_get_channel_id(instance),
ast_sockaddr_stringify(sa));
return 0;
}
/*
* If we got this far, then ice_active_remote_candidates
* can't be NULL.
*/
i = ao2_iterator_init(rtp->ice_active_remote_candidates, 0);
while ((candidate = ao2_iterator_next(&i)) && (cand_cnt < PJ_ICE_MAX_CAND)) {
res = ast_sockaddr_cmp_addr(&candidate->address, sa);
ao2_ref(candidate, -1);
if (res == 0) {
pass_src_check = 1;
break;
}
cand_cnt++;
}
ao2_iterator_destroy(&i);
if (!pass_src_check) {
ast_log(LOG_WARNING, "%s: DTLS packet from %s dropped. Source not in ICE active candidate list.\n",
ast_rtp_instance_get_channel_id(instance),
ast_sockaddr_stringify(sa));
return 0;
}
}
/*
* A race condition is prevented between dtls_perform_handshake()
* and this function because both functions have to get the