autoupdater: uclient: fix segfault after interrupted HTTP request

uloop_run() may finish without ever reaching request_done(), for example
when the main loop is interrupted by a signal. In this case,
uclient_disconnect() was never called, leaving a number of callbacks
like timeout handlers registered in the uloop context.

When the main loop was later resumed in a subsequent HTTP request without
completely reinitializing the uloop context, these timeout handlers could
still fire, even though the old uclient context had already been freed,
resulting in a use-after-free.

To avoid this, move the uclient_disconnect() call out of request_done()
to ensure that it is always called before uclient_free().
This commit is contained in:
Matthias Schiffer 2023-02-24 20:41:09 +01:00
parent 5521926500
commit e4bd7a4549
No known key found for this signature in database
GPG Key ID: 16EF3F64CB201D9C
1 changed files with 3 additions and 2 deletions

View File

@ -74,7 +74,6 @@ const char *uclient_get_errmsg(int code) {
static void request_done(struct uclient *cl, int err_code) {
uclient_data(cl)->err_code = err_code;
uclient_disconnect(cl);
uloop_end();
}
@ -192,8 +191,10 @@ int get_url(const char *url, void (*read_cb)(struct uclient *cl), void *cb_data,
ret = d.err_code;
err:
if (cl)
if (cl) {
uclient_disconnect(cl);
uclient_free(cl);
}
return ret;
}