diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-05-01 10:00:00 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-05-01 10:00:00 +0100 |
commit | 84aaf4530b7d495668fb2c69fdd6f5c28533c1ac (patch) | |
tree | cb246156ea962092bef37df767ef8fbaeeba043f /tools/xenstore | |
parent | a2f23ae851a744beb582ab4f11d654516fde1e78 (diff) | |
download | xen-84aaf4530b7d495668fb2c69fdd6f5c28533c1ac.tar.gz xen-84aaf4530b7d495668fb2c69fdd6f5c28533c1ac.tar.bz2 xen-84aaf4530b7d495668fb2c69fdd6f5c28533c1ac.zip |
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>
Diffstat (limited to 'tools/xenstore')
-rw-r--r-- | tools/xenstore/xenstored_core.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 657322ab8c..b391319a15 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -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, |