aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-08-16 07:06:10 +0000
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-08-16 07:06:10 +0000
commit12ef0a954828fabf654cb360c65a72905ceaaf7e (patch)
tree49018a7ce365b8e5337bd4bddef98488cbac6a0a
parent3168022e9e290d53de28b9e2d9fb3aa906c1ab92 (diff)
downloadxen-12ef0a954828fabf654cb360c65a72905ceaaf7e.tar.gz
xen-12ef0a954828fabf654cb360c65a72905ceaaf7e.tar.bz2
xen-12ef0a954828fabf654cb360c65a72905ceaaf7e.zip
Under the right circumstances, xenconsoled will corrupt its internal
list of domains causing a SEGV. This is usually characterized by a rapid number of creations/destructions. The attached patch fixes this. 1) Fix uninitialized next pointer. This could sometimes cause xenconsoled to SEGV on an invalid domain pointer 2) Fix race condition in iterating domain list where removing a domain in a callback could lead to the iterators becoming invalid. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r--tools/console/daemon/io.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index 87c3cc06e6..f334458e55 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -87,6 +87,7 @@ struct domain
{
int domid;
int tty_fd;
+ bool is_dead;
struct buffer buffer;
struct domain *next;
};
@@ -156,10 +157,12 @@ static struct domain *create_domain(int domid)
dom->domid = domid;
dom->tty_fd = domain_create_tty(dom);
+ dom->is_dead = false;
dom->buffer.data = 0;
dom->buffer.size = 0;
dom->buffer.capacity = 0;
dom->buffer.max_capacity = 0;
+ dom->next = 0;
dolog(LOG_DEBUG, "New domain %d", domid);
@@ -206,6 +209,16 @@ static void remove_domain(struct domain *dom)
}
}
+static void remove_dead_domains(struct domain *dom)
+{
+ if (dom == NULL) return;
+ remove_dead_domains(dom->next);
+
+ if (dom->is_dead) {
+ remove_domain(dom);
+ }
+}
+
static void handle_tty_read(struct domain *dom)
{
ssize_t len;
@@ -224,7 +237,7 @@ static void handle_tty_read(struct domain *dom)
if (domain_is_valid(dom->domid)) {
dom->tty_fd = domain_create_tty(dom);
} else {
- remove_domain(dom);
+ dom->is_dead = true;
}
} else if (domain_is_valid(dom->domid)) {
msg.u.control.msg.length = len;
@@ -235,7 +248,7 @@ static void handle_tty_read(struct domain *dom)
}
} else {
close(dom->tty_fd);
- remove_domain(dom);
+ dom->is_dead = true;
}
}
@@ -250,7 +263,7 @@ static void handle_tty_write(struct domain *dom)
if (domain_is_valid(dom->domid)) {
dom->tty_fd = domain_create_tty(dom);
} else {
- remove_domain(dom);
+ dom->is_dead = true;
}
} else {
buffer_advance(&dom->buffer, len);
@@ -333,13 +346,15 @@ void handle_io(void)
}
for (d = dom_head; d; d = d->next) {
- if (FD_ISSET(d->tty_fd, &readfds)) {
+ if (!d->is_dead && FD_ISSET(d->tty_fd, &readfds)) {
handle_tty_read(d);
}
- if (FD_ISSET(d->tty_fd, &writefds)) {
+ if (!d->is_dead && FD_ISSET(d->tty_fd, &writefds)) {
handle_tty_write(d);
}
}
+
+ remove_dead_domains(dom_head);
} while (ret > -1);
}