summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Coquelin <maxime.coquelin@redhat.com>2019-09-03 17:34:22 +0200
committerLuca Boccassi <luca.boccassi@microsoft.com>2019-11-07 15:28:50 +0000
commit1f6147d9a01fdc9c1c5baff3d8f71451d664212c (patch)
tree448f2fbac308cedfe7dc5efe8017393ebdef7c95
parent8a8dbd0ec19eb735060f33751a3fda5bd6de0578 (diff)
downloaddpdk-stable-1f6147d9a01f.zip
dpdk-stable-1f6147d9a01f.tar.gz
dpdk-stable-1f6147d9a01f.tar.xz
vhost: fix possible denial of service by leaking FDs
A malicious Vhost-user master could send in loop hand-crafted vhost-user messages containing more file descriptors the vhost-user slave expects. Doing so causes the application using the vhost-user library to run out of FDs. This issue has been assigned CVE-2019-14818 Fixes: 8f972312b8f4 ("vhost: support vhost-user") Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
-rw-r--r--lib/librte_vhost/vhost_user.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
index 781734e..d4643dc 100644
--- a/lib/librte_vhost/vhost_user.c
+++ b/lib/librte_vhost/vhost_user.c
@@ -81,6 +81,36 @@ static const char *vhost_message_str[VHOST_USER_MAX] = {
[VHOST_USER_IOTLB_MSG] = "VHOST_USER_IOTLB_MSG",
};
+static void
+close_msg_fds(struct VhostUserMsg *msg)
+{
+ int i;
+
+ for (i = 0; i < msg->fd_num; i++)
+ close(msg->fds[i]);
+}
+
+/*
+ * Ensure the expected number of FDs is received,
+ * close all FDs and return an error if this is not the case.
+ */
+static int
+validate_msg_fds(struct VhostUserMsg *msg, int expected_fds)
+{
+ if (msg->fd_num == expected_fds)
+ return 0;
+
+ RTE_LOG(ERR, VHOST_CONFIG,
+ " Expect %d FDs for request %s, received %d\n",
+ expected_fds,
+ vhost_message_str[msg->request.master],
+ msg->fd_num);
+
+ close_msg_fds(msg);
+
+ return -1;
+}
+
static uint64_t
get_blk_size(int fd)
{
@@ -1458,34 +1488,58 @@ vhost_user_msg_handler(int vid, int fd)
switch (msg.request.master) {
case VHOST_USER_GET_FEATURES:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
msg.payload.u64 = vhost_user_get_features(dev);
msg.size = sizeof(msg.payload.u64);
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_FEATURES:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_set_features(dev, msg.payload.u64);
break;
case VHOST_USER_GET_PROTOCOL_FEATURES:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_get_protocol_features(dev, &msg);
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_PROTOCOL_FEATURES:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_set_protocol_features(dev, msg.payload.u64);
break;
case VHOST_USER_SET_OWNER:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_set_owner();
break;
case VHOST_USER_RESET_OWNER:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_reset_owner(dev);
break;
case VHOST_USER_SET_MEM_TABLE:
+ if (validate_msg_fds(&msg, msg.payload.memory.nregions) != 0)
+ return -1;
+
ret = vhost_user_set_mem_table(&dev, &msg);
break;
case VHOST_USER_SET_LOG_BASE:
+ if (validate_msg_fds(&msg, 1) != 0)
+ return -1;
+
vhost_user_set_log_base(dev, &msg);
/*
@@ -1496,61 +1550,102 @@ vhost_user_msg_handler(int vid, int fd)
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_LOG_FD:
+ if (validate_msg_fds(&msg, 1) != 0)
+ return -1;
+
close(msg.fds[0]);
RTE_LOG(INFO, VHOST_CONFIG, "not implemented.\n");
break;
case VHOST_USER_SET_VRING_NUM:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_set_vring_num(dev, &msg);
break;
case VHOST_USER_SET_VRING_ADDR:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_set_vring_addr(&dev, &msg);
break;
case VHOST_USER_SET_VRING_BASE:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_set_vring_base(dev, &msg);
break;
case VHOST_USER_GET_VRING_BASE:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_get_vring_base(dev, &msg);
msg.size = sizeof(msg.payload.state);
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_VRING_KICK:
+ if (validate_msg_fds(&msg, 1) != 0)
+ return -1;
+
vhost_user_set_vring_kick(&dev, &msg);
break;
case VHOST_USER_SET_VRING_CALL:
+ if (validate_msg_fds(&msg, 1) != 0)
+ return -1;
+
vhost_user_set_vring_call(dev, &msg);
break;
case VHOST_USER_SET_VRING_ERR:
+ if (validate_msg_fds(&msg, 1) != 0)
+ return -1;
+
if (!(msg.payload.u64 & VHOST_USER_VRING_NOFD_MASK))
close(msg.fds[0]);
RTE_LOG(INFO, VHOST_CONFIG, "not implemented\n");
break;
case VHOST_USER_GET_QUEUE_NUM:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
msg.payload.u64 = VHOST_MAX_QUEUE_PAIRS;
msg.size = sizeof(msg.payload.u64);
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_VRING_ENABLE:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_set_vring_enable(dev, &msg);
break;
case VHOST_USER_SEND_RARP:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
vhost_user_send_rarp(dev, &msg);
break;
case VHOST_USER_NET_SET_MTU:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
ret = vhost_user_net_set_mtu(dev, &msg);
break;
case VHOST_USER_SET_SLAVE_REQ_FD:
+ if (validate_msg_fds(&msg, 1) != 0)
+ return -1;
+
ret = vhost_user_set_req_fd(dev, &msg);
break;
case VHOST_USER_IOTLB_MSG:
+ if (validate_msg_fds(&msg, 0) != 0)
+ return -1;
+
ret = vhost_user_iotlb_msg(&dev, &msg);
break;