mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
xemnstored: Fix xenstored abort when connection dropped.
If a connection is dropped with pending input and output data then the connection will be dereferenced by both handle_input and handle_output resulting in a double free when the main loop dereferences the connection. Fix this issue by taking/releasing a reference over the calls to handle_input and handle_output separately and checking the result of talloc_free to see if the connection went away. Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
a2f23ae851
commit
84aaf4530b
1 file changed
+21
-9
@@ -1929,7 +1929,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Main loop. */
|
||||
for (;;) {
|
||||
struct connection *conn, *old_conn;
|
||||
struct connection *conn, *next;
|
||||
|
||||
if (select(max+1, &inset, &outset, NULL, timeout) < 0) {
|
||||
if (errno == EINTR)
|
||||
@@ -1953,27 +1953,39 @@ int main(int argc, char *argv[])
|
||||
if (evtchn_fd != -1 && FD_ISSET(evtchn_fd, &inset))
|
||||
handle_event();
|
||||
|
||||
conn = list_entry(connections.next, typeof(*conn), list);
|
||||
while (&conn->list != &connections) {
|
||||
talloc_increase_ref_count(conn);
|
||||
next = list_entry(connections.next, typeof(*conn), list);
|
||||
while (&next->list != &connections) {
|
||||
conn = next;
|
||||
|
||||
next = list_entry(conn->list.next,
|
||||
typeof(*conn), list);
|
||||
|
||||
if (conn->domain) {
|
||||
talloc_increase_ref_count(conn);
|
||||
if (domain_can_read(conn))
|
||||
handle_input(conn);
|
||||
if (talloc_free(conn) == 0)
|
||||
continue;
|
||||
|
||||
talloc_increase_ref_count(conn);
|
||||
if (domain_can_write(conn) &&
|
||||
!list_empty(&conn->out_list))
|
||||
handle_output(conn);
|
||||
if (talloc_free(conn) == 0)
|
||||
continue;
|
||||
} else {
|
||||
talloc_increase_ref_count(conn);
|
||||
if (FD_ISSET(conn->fd, &inset))
|
||||
handle_input(conn);
|
||||
if (talloc_free(conn) == 0)
|
||||
continue;
|
||||
|
||||
talloc_increase_ref_count(conn);
|
||||
if (FD_ISSET(conn->fd, &outset))
|
||||
handle_output(conn);
|
||||
if (talloc_free(conn) == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
old_conn = conn;
|
||||
conn = list_entry(old_conn->list.next,
|
||||
typeof(*conn), list);
|
||||
talloc_free(old_conn);
|
||||
}
|
||||
|
||||
max = initialize_set(&inset, &outset, *sock, *ro_sock,
|
||||
|
||||