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:
Taylor R Campbell
2024-01-02 13:46:43 +00:00
committed by Nico Williams
parent f455ea9834
commit 3171398867

View File

@@ -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;
@@ -858,7 +862,7 @@ submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi)
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;