krb5: Fix use-after-free when debug is enabled with http_proxy.
Instead of freeing host->ai on return from submit_request in the http_proxy path, stash the proxy's ai in another member host->freeai which will be freed when host is freed. Assumption: All hosts created in submit_request cease to be used before any of them are freed, so it's safe to pick one host to hang the proxy's ai on and free the ai when that host is freed. fix https://github.com/heimdal/heimdal/issues/1205
This commit is contained in:

committed by
Nico Williams

parent
f455ea9834
commit
3171398867
@@ -328,6 +328,7 @@ struct host_fun {
|
|||||||
struct host {
|
struct host {
|
||||||
enum host_state { CONNECT, CONNECTING, CONNECTED, WAITING_REPLY, DEAD } state;
|
enum host_state { CONNECT, CONNECTING, CONNECTED, WAITING_REPLY, DEAD } state;
|
||||||
krb5_krbhst_info *hi;
|
krb5_krbhst_info *hi;
|
||||||
|
struct addrinfo *freeai;
|
||||||
struct addrinfo *ai;
|
struct addrinfo *ai;
|
||||||
rk_socket_t fd;
|
rk_socket_t fd;
|
||||||
const struct host_fun *fun;
|
const struct host_fun *fun;
|
||||||
@@ -393,6 +394,9 @@ deallocate_host(void *ptr)
|
|||||||
if (!rk_IS_BAD_SOCKET(host->fd))
|
if (!rk_IS_BAD_SOCKET(host->fd))
|
||||||
rk_closesocket(host->fd);
|
rk_closesocket(host->fd);
|
||||||
krb5_data_free(&host->data);
|
krb5_data_free(&host->data);
|
||||||
|
if (host->freeai)
|
||||||
|
freeaddrinfo(host->freeai);
|
||||||
|
host->freeai = NULL;
|
||||||
host->ai = NULL;
|
host->ai = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +804,7 @@ static krb5_error_code
|
|||||||
submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
|
submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
|
||||||
{
|
{
|
||||||
unsigned long submitted_host = 0;
|
unsigned long submitted_host = 0;
|
||||||
krb5_boolean freeai = FALSE;
|
struct addrinfo *freeai = NULL;
|
||||||
struct timeval nrstart, nrstop;
|
struct timeval nrstart, nrstop;
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
struct addrinfo *ai = NULL, *a;
|
struct addrinfo *ai = NULL, *a;
|
||||||
@@ -857,8 +861,8 @@ submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
|
|||||||
free(proxy2);
|
free(proxy2);
|
||||||
if (ret)
|
if (ret)
|
||||||
return krb5_eai_to_heim_errno(ret, errno);
|
return krb5_eai_to_heim_errno(ret, errno);
|
||||||
|
|
||||||
freeai = TRUE;
|
freeai = ai;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
|
ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
|
||||||
@@ -893,13 +897,15 @@ submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
|
|||||||
host = heim_alloc(sizeof(*host), "sendto-host", deallocate_host);
|
host = heim_alloc(sizeof(*host), "sendto-host", deallocate_host);
|
||||||
if (host == NULL) {
|
if (host == NULL) {
|
||||||
if (freeai)
|
if (freeai)
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(freeai);
|
||||||
rk_closesocket(fd);
|
rk_closesocket(fd);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
host->hi = hi;
|
host->hi = hi;
|
||||||
host->fd = fd;
|
host->fd = fd;
|
||||||
host->ai = a;
|
host->ai = a;
|
||||||
|
host->freeai = freeai;
|
||||||
|
freeai = NULL;
|
||||||
/* next version of stid */
|
/* next version of stid */
|
||||||
host->tid = ctx->stid = (ctx->stid & 0xffff0000) | ((ctx->stid & 0xffff) + 1);
|
host->tid = ctx->stid = (ctx->stid & 0xffff0000) | ((ctx->stid & 0xffff) + 1);
|
||||||
|
|
||||||
@@ -946,7 +952,7 @@ submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (freeai)
|
if (freeai)
|
||||||
freeaddrinfo(ai);
|
freeai = NULL;
|
||||||
|
|
||||||
if (submitted_host == 0)
|
if (submitted_host == 0)
|
||||||
return KRB5_KDC_UNREACH;
|
return KRB5_KDC_UNREACH;
|
||||||
|
Reference in New Issue
Block a user