80 lines
2.5 KiB
Diff
80 lines
2.5 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1209632400 -3600
|
|
# Node ID 5e5bc5b2bb6d4d71c0de97c15448f2f991f4271d
|
|
# Parent 2cf9a8736babe63fe1783286f666c3d6fc9af58b
|
|
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>
|
|
|
|
Index: xen-3.2.1-testing/tools/xenstore/xenstored_core.c
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/xenstore/xenstored_core.c
|
|
+++ xen-3.2.1-testing/tools/xenstore/xenstored_core.c
|
|
@@ -1915,7 +1915,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)
|
|
@@ -1939,27 +1939,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,
|