提交 5c52aed1 编写于 作者: P Pavel Hrdina

rpc: for messages with FDs always decode count of FDs from the message

The packet with passed FD has the following format:

    --------------------------
    | len | header | payload |
    --------------------------

where "payload" has an additional count of FDs before the actual data:

    ------------------
    | nfds | payload |
    ------------------

When the packet is received we parse the "header", which as a side
effect updates msg->bufferOffset to point to the beginning of "payload".
If the message call contains FDs, we need to also parse the count of
FDs, which also updates the msg->bufferOffset.

The issue here is that when we attempt to read the FDs data from the
socket and we receive EAGAIN we finish the reading and call poll()
to wait for the data the we need.  When the data arrives we already have
the packet in our buffer so we read the "header" again but this time
we don't read the count of FDs because we already have it stored.

That means that the msg->bufferOffset is not updated to point to the
actual beginning of the payload data, but it points to the count of
FDs.  After all FDs are processed we dispatch the message to process
it and decode the payload.  Since the msg->bufferOffset points to wrong
data, we decode the wrong payload and the API call fails with
error messages:

    Domain not found: no domain with matching uuid '67656e65-7269-6300-0c87-5003ca6941f2' ()

Broken by commit 133c511b which fixed a FD and memory leak.
Signed-off-by: NPavel Hrdina <phrdina@redhat.com>
上级 3685e2dd
...@@ -1428,8 +1428,7 @@ virNetClientIOHandleInput(virNetClientPtr client) ...@@ -1428,8 +1428,7 @@ virNetClientIOHandleInput(virNetClientPtr client)
if (client->msg.header.type == VIR_NET_REPLY_WITH_FDS) { if (client->msg.header.type == VIR_NET_REPLY_WITH_FDS) {
size_t i; size_t i;
if (client->msg.nfds == 0 && if (virNetMessageDecodeNumFDs(&client->msg) < 0)
virNetMessageDecodeNumFDs(&client->msg) < 0)
return -1; return -1;
for (i = client->msg.donefds; i < client->msg.nfds; i++) { for (i = client->msg.donefds; i < client->msg.nfds; i++) {
......
...@@ -327,11 +327,13 @@ int virNetMessageDecodeNumFDs(virNetMessagePtr msg) ...@@ -327,11 +327,13 @@ int virNetMessageDecodeNumFDs(virNetMessagePtr msg)
goto cleanup; goto cleanup;
} }
msg->nfds = numFDs; if (msg->nfds == 0) {
if (VIR_ALLOC_N(msg->fds, msg->nfds) < 0) msg->nfds = numFDs;
goto cleanup; if (VIR_ALLOC_N(msg->fds, msg->nfds) < 0)
for (i = 0; i < msg->nfds; i++) goto cleanup;
msg->fds[i] = -1; for (i = 0; i < msg->nfds; i++)
msg->fds[i] = -1;
}
VIR_DEBUG("Got %zu FDs from peer", msg->nfds); VIR_DEBUG("Got %zu FDs from peer", msg->nfds);
......
...@@ -1189,8 +1189,7 @@ static void virNetServerClientDispatchRead(virNetServerClientPtr client) ...@@ -1189,8 +1189,7 @@ static void virNetServerClientDispatchRead(virNetServerClientPtr client)
/* Now figure out if we need to read more data to get some /* Now figure out if we need to read more data to get some
* file descriptors */ * file descriptors */
if (msg->header.type == VIR_NET_CALL_WITH_FDS) { if (msg->header.type == VIR_NET_CALL_WITH_FDS) {
if (msg->nfds == 0 && if (virNetMessageDecodeNumFDs(msg) < 0) {
virNetMessageDecodeNumFDs(msg) < 0) {
virNetMessageQueueServe(&client->rx); virNetMessageQueueServe(&client->rx);
virNetMessageFree(msg); virNetMessageFree(msg);
client->wantClose = true; client->wantClose = true;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册