[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v3 13/17] libxl: use vchan for QMP access with Linux stubdomain, non-async version



Access to QMP of QEMU in Linux stubdomain is possible over vchan
connection. Add appropriate handling to synchronous API.
Since only one client can be connected to vchan server at the same time
and it is not enforced by the libxenvchan itself, additional client-side
locking is needed. Note that qemu supports only one simultaneous client
on a control socket anyway (but in UNIX socket case, it enforce it
server-side, so it doesn't add any extra limitation.

Ideally, I woudn't need (or want) this part, and would communicate with
stubdomain only with async API. But some libxl public functions that are
not async-compatible do need to call qmp commands (for example
libxl_domain_unpause). Alternative to this patch, would be return error,
breaking all such functions, and incrementally convert them to async
API.

Signed-off-by: Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx>
---

Two TODOs here:
 - handle locking, similarly to previous patch
 - select() qmp_next() can now be triggered by malicious stubdomain
   without actually sending any data, which would evade timeout
   enforcing (as select() each time is called with full timeout); the
   easiest thing to do, would be to re-use timeout value from previous
   select() call, but that works only on Linux; any better idea?
   Note that even without using vchan, malicious qemu could cause
   qmp_next() to wait almost indefinitely - by writing one byte at a
   time and never finishing the message

Changes in v3:
 - new patch, in place of "libxl: access QMP socket via console for
   qemu-in-stubdomain"
---
 tools/libxl/libxl_qmp.c | 61 ++++++++++++++++++++++++++++++++----------
 1 file changed, 47 insertions(+), 14 deletions(-)

diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
index 45b9f74..19ce3ce 100644
--- a/tools/libxl/libxl_qmp.c
+++ b/tools/libxl/libxl_qmp.c
@@ -113,6 +113,7 @@ typedef struct callback_id_pair {
 
 struct libxl__qmp_handler {
     int qmp_fd;
+    struct libxenvchan *vchan;
     bool connected;
     time_t timeout;
     /* wait_for_id will be used by the synchronous send function */
@@ -496,7 +497,10 @@ static void qmp_close(libxl__qmp_handler *qmp)
     callback_id_pair *pp = NULL;
     callback_id_pair *tmp = NULL;
 
-    close(qmp->qmp_fd);
+    if (qmp->vchan)
+        libxenvchan_close(qmp->vchan);
+    else
+        close(qmp->qmp_fd);
     LIBXL_STAILQ_FOREACH(pp, &qmp->callback_list, next) {
         free(tmp);
         tmp = pp;
@@ -516,7 +520,7 @@ static int qmp_next(libxl__gc *gc, libxl__qmp_handler *qmp)
 
     do {
         fd_set rfds;
-        int ret = 0;
+        int ret = 1; /* used when select() is skipped */
         struct timeval timeout = {
             .tv_sec = qmp->timeout,
             .tv_usec = 0,
@@ -525,7 +529,8 @@ static int qmp_next(libxl__gc *gc, libxl__qmp_handler *qmp)
         FD_ZERO(&rfds);
         FD_SET(qmp->qmp_fd, &rfds);
 
-        ret = select(qmp->qmp_fd + 1, &rfds, NULL, NULL, &timeout);
+        if (!(qmp->vchan && libxenvchan_data_ready(qmp->vchan)))
+            ret = select(qmp->qmp_fd + 1, &rfds, NULL, NULL, &timeout);
         if (ret == 0) {
             LOGD(ERROR, qmp->domid, "timeout");
             return -1;
@@ -536,7 +541,14 @@ static int qmp_next(libxl__gc *gc, libxl__qmp_handler *qmp)
             return -1;
         }
 
-        rd = read(qmp->qmp_fd, qmp->buffer, QMP_RECEIVE_BUFFER_SIZE);
+        if (qmp->vchan) {
+            libxenvchan_wait(qmp->vchan);
+            if (!libxenvchan_data_ready(qmp->vchan))
+                continue;
+            rd = libxenvchan_read(qmp->vchan, qmp->buffer, 
QMP_RECEIVE_BUFFER_SIZE);
+        } else {
+            rd = read(qmp->qmp_fd, qmp->buffer, QMP_RECEIVE_BUFFER_SIZE);
+        }
         if (rd == 0) {
             LOGD(ERROR, qmp->domid, "Unexpected end of socket");
             return -1;
@@ -684,9 +696,15 @@ static int qmp_send(libxl__qmp_handler *qmp,
         goto out;
     }
 
-    if (libxl_write_exactly(qmp->ctx, qmp->qmp_fd, buf, strlen(buf),
-                            "QMP command", "QMP socket"))
-        goto out;
+    if (qmp->vchan) {
+        /* vchan->blocking == 1, so no need to wrap it in a loop */
+        if (libxenvchan_write(qmp->vchan, buf, strlen(buf)) == -1)
+            goto out;
+    } else {
+        if (libxl_write_exactly(qmp->ctx, qmp->qmp_fd, buf, strlen(buf),
+                                "QMP command", "QMP socket"))
+            goto out;
+    }
 
     rc = qmp->last_id_used;
 out:
@@ -798,19 +816,34 @@ libxl__qmp_handler *libxl__qmp_initialize(libxl__gc *gc, 
uint32_t domid)
 {
     int ret = 0;
     libxl__qmp_handler *qmp = NULL;
-    char *qmp_socket;
+    int dm_domid;
+    char *qmp_path;
 
     qmp = qmp_init_handler(gc, domid);
     if (!qmp) return NULL;
 
-    qmp_socket = GCSPRINTF("%s/qmp-libxl-%d", libxl__run_dir_path(), domid);
-    if ((ret = qmp_open(qmp, qmp_socket, QMP_SOCKET_CONNECT_TIMEOUT)) < 0) {
-        LOGED(ERROR, domid, "Connection error");
-        qmp_free_handler(qmp);
-        return NULL;
+    dm_domid = libxl_get_stubdom_id(CTX, domid);
+    if (dm_domid) {
+        qmp_path = DEVICE_MODEL_XS_PATH(gc, dm_domid, domid, "/qmp-vchan");
+        /* TODO: add locking */
+        qmp->vchan = libxenvchan_client_init(CTX->lg, dm_domid, qmp_path);
+        if (!qmp->vchan) {
+            LOGED(ERROR, domid, "QMP vchan connection failed: %s", 
strerror(errno));
+            qmp_free_handler(qmp);
+            return NULL;
+        }
+        qmp->vchan->blocking = 1;
+        qmp->qmp_fd = libxenvchan_fd_for_select(qmp->vchan);
+    } else {
+        qmp_path = GCSPRINTF("%s/qmp-libxl-%d", libxl__run_dir_path(), domid);
+        if ((ret = qmp_open(qmp, qmp_path, QMP_SOCKET_CONNECT_TIMEOUT)) < 0) {
+            LOGED(ERROR, domid, "Connection error");
+            qmp_free_handler(qmp);
+            return NULL;
+        }
     }
 
-    LOGD(DEBUG, domid, "connected to %s", qmp_socket);
+    LOGD(DEBUG, domid, "connected to %s", qmp_path);
 
     /* Wait for the response to qmp_capabilities */
     while (!qmp->connected) {
-- 
git-series 0.9.1

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.