aboutsummaryrefslogtreecommitdiffstats
path: root/debian/patches/ubuntu-backport-33-vhost-user-add-error-handling-for-fd-1023.patch
blob: ea1ff75b9e914a89da022373e3f92ac22c98bc80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
Description: backport of dpdk fix for LP: #1566874

Forwarded: n/a (already discussed upstream)
Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Last-Update: 2016-04-11

Extended by Christian Ehrhardt <christian.ehrhardt@canonical.com>
Close fd on vserver->listenfd (Part of the upstream discussion)

Original:
From: Patrik Andersson <patrik.r.andersson@ericsson.com>

Protect against DPDK crash when allocation of listen fd >= 1023.
For events on fd:s >1023, the current implementation will trigger
an abort due to access outside of allocated bit mask.

Corrections would include:

  * Match fdset_add() signature in fd_man.c to fd_man.h
  * Handling of return codes from fdset_add()
  * Addition of check of fd number in fdset_add_fd()

The rationale behind the suggested code change is that,
fdset_event_dispatch() could attempt access outside of the FD_SET
bitmask if there is an event on a file descriptor that in turn
looks up a virtio file descriptor with a value > 1023.
Such an attempt will lead to an abort() and a restart of any
vswitch using DPDK.

A discussion topic exist in the ovs-discuss mailing list that can
provide a little more background:

http://openvswitch.org/pipermail/discuss/2016-February/020243.html

Signed-off-by: Patrik Andersson <patrik.r.andersson@ericsson.com>
---
 fd_man.c         |   11 ++++++-----
 vhost-net-user.c |   23 +++++++++++++++++++++--
 2 files changed, 27 insertions(+), 7 deletions(-)

Index: dpdk/lib/librte_vhost/vhost_user/fd_man.c
===================================================================
--- dpdk.orig/lib/librte_vhost/vhost_user/fd_man.c
+++ dpdk/lib/librte_vhost/vhost_user/fd_man.c
@@ -71,20 +71,22 @@ fdset_find_free_slot(struct fdset *pfdse
 	return fdset_find_fd(pfdset, -1);
 }
 
-static void
+static int
 fdset_add_fd(struct fdset  *pfdset, int idx, int fd,
 	fd_cb rcb, fd_cb wcb, void *dat)
 {
 	struct fdentry *pfdentry;
 
-	if (pfdset == NULL || idx >= MAX_FDS)
-		return;
+	if (pfdset == NULL || idx >= MAX_FDS || fd >= FD_SETSIZE)
+		return -1;
 
 	pfdentry = &pfdset->fd[idx];
 	pfdentry->fd = fd;
 	pfdentry->rcb = rcb;
 	pfdentry->wcb = wcb;
 	pfdentry->dat = dat;
+
+	return 0;
 }
 
 /**
@@ -150,12 +152,11 @@ fdset_add(struct fdset *pfdset, int fd,
 
 	/* Find a free slot in the list. */
 	i = fdset_find_free_slot(pfdset);
-	if (i == -1) {
+	if (i == -1 || fdset_add_fd(pfdset, i, fd, rcb, wcb, dat) < 0) {
 		pthread_mutex_unlock(&pfdset->fd_mutex);
 		return -2;
 	}
 
-	fdset_add_fd(pfdset, i, fd, rcb, wcb, dat);
 	pfdset->num++;
 
 	pthread_mutex_unlock(&pfdset->fd_mutex);
Index: dpdk/lib/librte_vhost/vhost_user/vhost-net-user.c
===================================================================
--- dpdk.orig/lib/librte_vhost/vhost_user/vhost-net-user.c
+++ dpdk/lib/librte_vhost/vhost_user/vhost-net-user.c
@@ -288,6 +288,7 @@ vserver_new_vq_conn(int fd, void *dat, _
 	int fh;
 	struct vhost_device_ctx vdev_ctx = { (pid_t)0, 0 };
 	unsigned int size;
+	int ret;
 
 	conn_fd = accept(fd, NULL, NULL);
 	RTE_LOG(INFO, VHOST_CONFIG,
@@ -317,8 +318,15 @@ vserver_new_vq_conn(int fd, void *dat, _
 
 	ctx->vserver = vserver;
 	ctx->fh = fh;
-	fdset_add(&g_vhost_server.fdset,
+	ret = fdset_add(&g_vhost_server.fdset,
 		conn_fd, vserver_message_handler, NULL, ctx);
+	if (ret < 0) {
+		free(ctx);
+		close(conn_fd);
+		RTE_LOG(ERR, VHOST_CONFIG,
+				"failed to add fd %d into vhost server fdset\n",
+				conn_fd);
+	}
 }
 
 /* callback when there is message on the connfd */
@@ -453,6 +461,7 @@ int
 rte_vhost_driver_register(const char *path)
 {
 	struct vhost_server *vserver;
+	int ret;
 
 	pthread_mutex_lock(&g_vhost_server.server_mutex);
 
@@ -478,8 +487,18 @@ rte_vhost_driver_register(const char *pa
 
 	vserver->path = strdup(path);
 
-	fdset_add(&g_vhost_server.fdset, vserver->listenfd,
+	ret = fdset_add(&g_vhost_server.fdset, vserver->listenfd,
 		vserver_new_vq_conn, NULL, vserver);
+	if (ret < 0) {
+		pthread_mutex_unlock(&g_vhost_server.server_mutex);
+		RTE_LOG(ERR, VHOST_CONFIG,
+				"failed to add listen fd %d to vhost server fdset\n",
+				vserver->listenfd);
+		close(vserver->listenfd);
+		free(vserver->path);
+		free(vserver);
+		return -1;
+	}
 
 	g_vhost_server.server[g_vhost_server.vserver_cnt++] = vserver;
 	pthread_mutex_unlock(&g_vhost_server.server_mutex);