RADIUS client: Fix crash issue in radius_client_timer()
While iterating through RADIUS messages in radius_client_timer(), one message entry may get flushed by "radius_client_retransmit --> radius_client_handle_send_error --> radius_client_init_auth --> radius_change_server --> radius_client_flush". This could result in freed memory being accessed afterwards. Signed-off-by: Jerry Yang <xyang@sonicwall.com>
This commit is contained in:
parent
c1fb75a6e2
commit
d045cc8e4c
1 changed files with 29 additions and 6 deletions
|
@ -295,8 +295,12 @@ int radius_client_register(struct radius_client_data *radius,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void radius_client_handle_send_error(struct radius_client_data *radius,
|
/*
|
||||||
int s, RadiusType msg_type)
|
* Returns >0 if message queue was flushed (i.e., the message that triggered
|
||||||
|
* the error is not available anymore)
|
||||||
|
*/
|
||||||
|
static int radius_client_handle_send_error(struct radius_client_data *radius,
|
||||||
|
int s, RadiusType msg_type)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_NATIVE_WINDOWS
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
int _errno = errno;
|
int _errno = errno;
|
||||||
|
@ -309,12 +313,18 @@ static void radius_client_handle_send_error(struct radius_client_data *radius,
|
||||||
" try to connect again");
|
" try to connect again");
|
||||||
eloop_unregister_read_sock(s);
|
eloop_unregister_read_sock(s);
|
||||||
close(s);
|
close(s);
|
||||||
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
|
if (msg_type == RADIUS_ACCT ||
|
||||||
|
msg_type == RADIUS_ACCT_INTERIM) {
|
||||||
radius_client_init_acct(radius);
|
radius_client_init_acct(radius);
|
||||||
else
|
return 0;
|
||||||
|
} else {
|
||||||
radius_client_init_auth(radius);
|
radius_client_init_auth(radius);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,8 +363,11 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
|
|
||||||
os_get_reltime(&entry->last_attempt);
|
os_get_reltime(&entry->last_attempt);
|
||||||
buf = radius_msg_get_buf(entry->msg);
|
buf = radius_msg_get_buf(entry->msg);
|
||||||
if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
|
if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
|
||||||
radius_client_handle_send_error(radius, s, entry->msg_type);
|
if (radius_client_handle_send_error(radius, s, entry->msg_type)
|
||||||
|
> 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
entry->next_try = now + entry->next_wait;
|
entry->next_try = now + entry->next_wait;
|
||||||
entry->next_wait *= 2;
|
entry->next_wait *= 2;
|
||||||
|
@ -378,6 +391,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
struct radius_msg_list *entry, *prev, *tmp;
|
struct radius_msg_list *entry, *prev, *tmp;
|
||||||
int auth_failover = 0, acct_failover = 0;
|
int auth_failover = 0, acct_failover = 0;
|
||||||
char abuf[50];
|
char abuf[50];
|
||||||
|
size_t prev_num_msgs;
|
||||||
|
|
||||||
entry = radius->msgs;
|
entry = radius->msgs;
|
||||||
if (!entry)
|
if (!entry)
|
||||||
|
@ -388,6 +402,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
while (entry) {
|
while (entry) {
|
||||||
|
prev_num_msgs = radius->num_msgs;
|
||||||
if (now.sec >= entry->next_try &&
|
if (now.sec >= entry->next_try &&
|
||||||
radius_client_retransmit(radius, entry, now.sec)) {
|
radius_client_retransmit(radius, entry, now.sec)) {
|
||||||
if (prev)
|
if (prev)
|
||||||
|
@ -402,6 +417,14 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prev_num_msgs != radius->num_msgs) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Message removed from queue - restart from beginning");
|
||||||
|
entry = radius->msgs;
|
||||||
|
prev = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
|
if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
|
||||||
if (entry->msg_type == RADIUS_ACCT ||
|
if (entry->msg_type == RADIUS_ACCT ||
|
||||||
entry->msg_type == RADIUS_ACCT_INTERIM)
|
entry->msg_type == RADIUS_ACCT_INTERIM)
|
||||||
|
|
Loading…
Reference in a new issue