ab3d6322f7a65b5fef69b493848ec5e4f6e85c65
[deb_dpdk.git] / debian / patches / ubuntu-fix-vhost-user-socket-permission.patch
1 Description: eal: provide option to set vhost_user socket owner/permissions
2
3 The API doesn't hold a way to specify a owner/permission set for vhost_user
4 created sockets.
5
6 Projects consuming DPDK started to do 'their own workarounds' like openvswitch
7 https://patchwork.ozlabs.org/patch/559043/
8 https://patchwork.ozlabs.org/patch/559045/
9 But for this specific example they are blocked/stalled behind a bigger
10 rework (https://patchwork.ozlabs.org/patch/604898/).
11
12 We need something now for existing code linking against DPDK. That implies to
13 avoid changing API/ABI. So I created a DPDK EAL commandline option based ideas
14 in the former patches.
15
16 Fixes LP: #1546565
17
18 *Update*
19  - with the split libs it now nees to be listed in
20    lib/librte_eal/linuxapp/eal/rte_eal_version.map to work on link steps
21  - please note that upstream gravitates towards not extending but creating a
22    new the API in DPDK as long term solution (will take a while)
23  - also as listed before most affected projects seem to create their own
24    workaround.
25  So over time we have to check when we can drop it at the price of a config
26  transition - likely OVS 2.6 won't need it anymore.
27
28 Forwarded: yes
29 Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
30 Last-Update: 2016-07-25
31
32 diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
33 index 7712bd2..28776b9 100644
34 --- a/doc/guides/testpmd_app_ug/run_app.rst
35 +++ b/doc/guides/testpmd_app_ug/run_app.rst
36 @@ -156,6 +156,25 @@ See the DPDK Getting Started Guides for more information on these options.
37  
38      Use malloc instead of hugetlbfs.
39  
40 +*   ``--vhost-owner``
41 +
42 +     When creating vhost_user sockets change owner and group to the specified value.
43 +     This can be given as ``user:group``, but also only ``user`` or ``:group`` are supported.
44 +
45 +    Examples::
46 +
47 +       --vhost-owner 'libvirt-qemu:kvm'
48 +       --vhost-owner 'libvirt-qemu'
49 +       --vhost-owner ':kvm'
50 +
51 +*   ``--vhost-perm``
52 +
53 +    When creating vhost_user sockets set them up with these permissions.
54 +
55 +    For example::
56 +
57 +       --vhost-perm '0664'
58 +
59  
60  Testpmd Command-line Options
61  ----------------------------
62 diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
63 index 481c732..2126140 100644
64 --- a/lib/librte_eal/common/eal_common_options.c
65 +++ b/lib/librte_eal/common/eal_common_options.c
66 @@ -95,6 +95,8 @@ eal_long_options[] = {
67         {OPT_VFIO_INTR,         1, NULL, OPT_VFIO_INTR_NUM        },
68         {OPT_VMWARE_TSC_MAP,    0, NULL, OPT_VMWARE_TSC_MAP_NUM   },
69         {OPT_XEN_DOM0,          0, NULL, OPT_XEN_DOM0_NUM         },
70 +       {OPT_VHOST_OWNER,       1, NULL, OPT_VHOST_OWNER_NUM      },
71 +       {OPT_VHOST_PERM,        1, NULL, OPT_VHOST_PERM_NUM       },
72         {0,                     0, NULL, 0                        }
73  };
74  
75 @@ -166,6 +168,8 @@ eal_reset_internal_config(struct internal_config *internal_cfg)
76  #endif
77         internal_cfg->vmware_tsc_map = 0;
78         internal_cfg->create_uio_dev = 0;
79 +       internal_cfg->vhost_sock_owner = NULL;
80 +       internal_cfg->vhost_sock_perm = NULL;
81  }
82  
83  static int
84 diff --git a/lib/librte_eal/common/eal_internal_cfg.h b/lib/librte_eal/common/eal_internal_cfg.h
85 index 5f1367e..bdf34e3 100644
86 --- a/lib/librte_eal/common/eal_internal_cfg.h
87 +++ b/lib/librte_eal/common/eal_internal_cfg.h
88 @@ -83,6 +83,8 @@ struct internal_config {
89         volatile enum rte_intr_mode vfio_intr_mode;
90         const char *hugefile_prefix;      /**< the base filename of hugetlbfs files */
91         const char *hugepage_dir;         /**< specific hugetlbfs directory to use */
92 +       const char *vhost_sock_owner;     /**< owner:group of vhost_user sockets */
93 +       const char *vhost_sock_perm;      /**< permissions of vhost_user sockets */
94  
95         unsigned num_hugepage_sizes;      /**< how many sizes on this system */
96         struct hugepage_info hugepage_info[MAX_HUGEPAGE_SIZES];
97 diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h
98 index a881c62..1161083 100644
99 --- a/lib/librte_eal/common/eal_options.h
100 +++ b/lib/librte_eal/common/eal_options.h
101 @@ -83,6 +83,10 @@ enum {
102         OPT_VMWARE_TSC_MAP_NUM,
103  #define OPT_XEN_DOM0          "xen-dom0"
104         OPT_XEN_DOM0_NUM,
105 +#define OPT_VHOST_OWNER       "vhost-owner"
106 +       OPT_VHOST_OWNER_NUM,
107 +#define OPT_VHOST_PERM        "vhost-perm"
108 +       OPT_VHOST_PERM_NUM,
109         OPT_LONG_MAX_NUM
110  };
111  
112 diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
113 index a71d6f5..506cf24 100644
114 --- a/lib/librte_eal/common/include/rte_eal.h
115 +++ b/lib/librte_eal/common/include/rte_eal.h
116 @@ -252,6 +252,11 @@ static inline int rte_gettid(void)
117         return RTE_PER_LCORE(_thread_id);
118  }
119  
120 +/**
121 + * Set owner/permissions on sockets if requested on EAL commandline
122 + */
123 +void rte_eal_set_socket_permissions(const char *);
124 +
125  #ifdef __cplusplus
126  }
127  #endif
128 diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
129 index 3fb2188..dc84c5b 100644
130 --- a/lib/librte_eal/linuxapp/eal/eal.c
131 +++ b/lib/librte_eal/linuxapp/eal/eal.c
132 @@ -53,6 +53,9 @@
133  #if defined(RTE_ARCH_X86)
134  #include <sys/io.h>
135  #endif
136 +#include <sys/types.h>
137 +#include <pwd.h>
138 +#include <grp.h>
139  
140  #include <rte_common.h>
141  #include <rte_debug.h>
142 @@ -344,6 +347,8 @@ eal_usage(const char *prgname)
143                "  --"OPT_CREATE_UIO_DEV"    Create /dev/uioX (usually done by hotplug)\n"
144                "  --"OPT_VFIO_INTR"         Interrupt mode for VFIO (legacy|msi|msix)\n"
145                "  --"OPT_XEN_DOM0"          Support running on Xen dom0 without hugetlbfs\n"
146 +              "  --"OPT_VHOST_OWNER"       Create vhost-user sockets with this owner:group\n"
147 +              "  --"OPT_VHOST_PERM"        Create vhost-user sockets with these permissions\n"
148                "\n");
149         /* Allow the application to print its usage message too if hook is set */
150         if ( rte_application_usage_hook ) {
151 @@ -601,6 +606,14 @@ eal_parse_args(int argc, char **argv)
152                         internal_config.create_uio_dev = 1;
153                         break;
154  
155 +               case OPT_VHOST_OWNER_NUM:
156 +                       internal_config.vhost_sock_owner = optarg;
157 +                       break;
158 +
159 +               case OPT_VHOST_PERM_NUM:
160 +                       internal_config.vhost_sock_perm = optarg;
161 +                       break;
162 +
163                 default:
164                         if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
165                                 RTE_LOG(ERR, EAL, "Option %c is not supported "
166 @@ -943,3 +956,172 @@ rte_eal_check_module(const char *module_name)
167         /* Module has been found */
168         return 1;
169  }
170 +
171 +/* Try to double the size of '*buf', return true
172 + * if successful, and '*sizep' will be updated with
173 + * the new size. Otherwise, return false.  */
174 +static int
175 +enlarge_buffer(char **buf, size_t *sizep)
176 +{
177 +    size_t newsize = *sizep * 2;
178 +
179 +    if (newsize > *sizep) {
180 +        *buf = realloc(*buf, newsize);
181 +        *sizep = newsize;
182 +        return 1;
183 +    }
184 +
185 +    return 0;
186 +}
187 +
188 +static int
189 +get_owners_from_str(const char *user_spec, uid_t *uid, gid_t *gid)
190 +{
191 +       size_t bufsize = 4096;
192 +
193 +       char *pos = strchr(user_spec, ':');
194 +       user_spec += strspn(user_spec, " \t\r\n");
195 +       size_t len = pos ? (size_t)(pos - user_spec) : strlen(user_spec);
196 +
197 +       char *buf = NULL;
198 +       struct passwd pwd, *res;
199 +       int e;
200 +
201 +       buf = malloc(bufsize);
202 +       char *user_search = NULL;
203 +       if (len) {
204 +               user_search = malloc(len + 1);
205 +               memcpy(user_search, user_spec, len);
206 +               user_search[len] = '\0';
207 +               while ((e = getpwnam_r(user_search, &pwd, buf, bufsize, &res)) == ERANGE) {
208 +                       if (!enlarge_buffer(&buf, &bufsize)) {
209 +                               break;
210 +                       }
211 +               }
212 +
213 +               if (e != 0) {
214 +                       RTE_LOG(ERR, EAL,"Failed to retrive user %s's uid (%s), aborting.",
215 +                               user_search, strerror(e));
216 +                       goto release;
217 +               }
218 +               if (res == NULL) {
219 +                       RTE_LOG(ERR, EAL,"user %s not found,  aborting.",
220 +                               user_search);
221 +                       e = -1;
222 +                       goto release;
223 +               }
224 +       } else {
225 +               /* User name is not specified, use current user.  */
226 +               while ((e = getpwuid_r(getuid(), &pwd, buf, bufsize, &res)) == ERANGE) {
227 +                       if (!enlarge_buffer(&buf, &bufsize)) {
228 +                               break;
229 +                       }
230 +               }
231 +
232 +               if (e != 0) {
233 +                       RTE_LOG(ERR, EAL,"Failed to retrive current user's uid "
234 +                               "(%s), aborting.", strerror(e));
235 +                       goto release;
236 +               }
237 +               user_search = strdup(pwd.pw_name);
238 +       }
239 +
240 +       if (uid)
241 +               *uid = pwd.pw_uid;
242 +
243 +       free(buf);
244 +       buf = NULL;
245 +
246 +       if (pos) {
247 +               char *grpstr = pos + 1;
248 +               grpstr += strspn(grpstr, " \t\r\n");
249 +
250 +               if (*grpstr) {
251 +                       struct group grp, *res;
252 +
253 +                       bufsize = 4096;
254 +                       buf = malloc(bufsize);
255 +                       while ((e = getgrnam_r(grpstr, &grp, buf, bufsize, &res))
256 +                                        == ERANGE) {
257 +                               if (!enlarge_buffer(&buf, &bufsize)) {
258 +                                       break;
259 +                               }
260 +                       }
261 +
262 +                       if (e) {
263 +                               RTE_LOG(ERR, EAL,"Failed to get group entry for %s, "
264 +                                       "(%s), aborting.", grpstr,
265 +                                       strerror(e));
266 +                               goto release;
267 +                       }
268 +                       if (res == NULL) {
269 +                               RTE_LOG(ERR, EAL,"Group %s not found, aborting.",
270 +                                       grpstr);
271 +                               e = -1;
272 +                               goto release;
273 +                       }
274 +
275 +                       if (gid)
276 +                               *gid = grp.gr_gid;
277 +               }
278 +       }
279 +
280 + release:
281 +       free(buf);
282 +       free(user_search);
283 +       return e;
284 +}
285 +
286 +static void
287 +vhost_set_permissions(const char *vhost_sock_location)
288 +{
289 +       unsigned long int mode = strtoul(internal_config.vhost_sock_perm, NULL, 0);
290 +       int err = chmod(vhost_sock_location, (mode_t)mode);
291 +       if (err) {
292 +               RTE_LOG(ERR, EAL,"vhost-user socket cannot set"
293 +                       " permissions to %s (%s).\n",
294 +                       internal_config.vhost_sock_perm, strerror(err));
295 +               return;
296 +       }
297 +       RTE_LOG(INFO, EAL,"Socket %s changed permissions"
298 +                       " to %s\n", vhost_sock_location,
299 +                       internal_config.vhost_sock_perm);
300 +}
301 +
302 +static void
303 +vhost_set_ownership(const char *vhost_sock_location)
304 +{
305 +       uid_t vhuid=0;
306 +       gid_t vhgid=0;
307 +
308 +       if (get_owners_from_str(internal_config.vhost_sock_owner, &vhuid, &vhgid)) {
309 +               RTE_LOG(ERR, EAL,"vhost-user socket unable to get"
310 +                       " specified user/group: %s\n",
311 +                       internal_config.vhost_sock_owner);
312 +               return;
313 +       }
314 +
315 +       int err = chown(vhost_sock_location, vhuid, vhgid);
316 +       if (err) {
317 +               RTE_LOG(ERR, EAL,"vhost-user socket unable to set"
318 +                       " ownership to %s (%s).\n",
319 +                       internal_config.vhost_sock_owner, strerror(err));
320 +               return;
321 +       }
322 +
323 +       RTE_LOG(INFO, EAL,"Socket %s changed ownership"
324 +                       " to %s.\n", vhost_sock_location,
325 +                       internal_config.vhost_sock_owner);
326 +}
327 +
328 +void
329 +rte_eal_set_socket_permissions(const char *path)
330 +{
331 +       if (internal_config.vhost_sock_perm) {
332 +               vhost_set_permissions(path);
333 +       }
334 +
335 +       if (internal_config.vhost_sock_owner) {
336 +               vhost_set_ownership(path);
337 +       }
338 +}
339 diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
340 index db8c984..bb92e57 100644
341 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
342 +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
343 @@ -139,6 +139,7 @@ DPDK_2.2 {
344         rte_keepalive_register_core;
345         rte_xen_dom0_supported;
346         rte_xen_mem_phy2mch;
347 +       rte_eal_set_socket_permissions;
348  
349  } DPDK_2.1;
350  
351 diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
352 index b35594d..dbdb8ad 100644
353 --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
354 +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
355 @@ -79,6 +79,8 @@ struct vhost_user {
356         pthread_mutex_t mutex;
357  };
358  
359 +#include <rte_eal.h>
360 +
361  #define MAX_VIRTIO_BACKLOG 128
362  
363  static void vhost_user_server_new_connection(int fd, void *data, int *remove);
364 @@ -682,6 +684,7 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
365         if (!vsocket)
366                 goto out;
367         memset(vsocket, 0, sizeof(struct vhost_user_socket));
368 +       rte_eal_set_socket_permissions(path);
369         vsocket->path = strdup(path);
370         vsocket->connfd = -1;
371