Fix d/p/fix-vhost-user-socket-permission.patch
[deb_dpdk.git] / debian / patches / 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 *Update*
29  - the handling and lifecycle of this changed in Openvswitch 2.7 so we can no
30    more use internal_config.
31  - Also the upstreaming was aborted as that now clearly goes towards client
32    mode vhost sockets for this (and other issues).
33  - But until that is fully working we have to carry the workaround.
34  - Updated to work with Openvswitch 2.7 (and backward compatible to 2.6)
35
36 *Update*
37  - in 17.05 the patch now needs to be hooked up on a different place in vhost
38    socket.c
39  - also the former rebase dropped a create socket call which is now restored
40
41 Forwarded: yes
42 Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
43 Last-Update: 2017-08-23
44
45 --- a/doc/guides/testpmd_app_ug/run_app.rst
46 +++ b/doc/guides/testpmd_app_ug/run_app.rst
47 @@ -156,6 +156,25 @@ See the DPDK Getting Started Guides for
48  
49      Use malloc instead of hugetlbfs.
50  
51 +*   ``--vhost-owner``
52 +
53 +     When creating vhost_user sockets change owner and group to the specified value.
54 +     This can be given as ``user:group``, but also only ``user`` or ``:group`` are supported.
55 +
56 +    Examples::
57 +
58 +       --vhost-owner 'libvirt-qemu:kvm'
59 +       --vhost-owner 'libvirt-qemu'
60 +       --vhost-owner ':kvm'
61 +
62 +*   ``--vhost-perm``
63 +
64 +    When creating vhost_user sockets set them up with these permissions.
65 +
66 +    For example::
67 +
68 +       --vhost-perm '0664'
69 +
70  
71  Testpmd Command-line Options
72  ----------------------------
73 --- a/lib/librte_eal/common/eal_common_options.c
74 +++ b/lib/librte_eal/common/eal_common_options.c
75 @@ -95,6 +95,8 @@ eal_long_options[] = {
76         {OPT_VFIO_INTR,         1, NULL, OPT_VFIO_INTR_NUM        },
77         {OPT_VMWARE_TSC_MAP,    0, NULL, OPT_VMWARE_TSC_MAP_NUM   },
78         {OPT_XEN_DOM0,          0, NULL, OPT_XEN_DOM0_NUM         },
79 +       {OPT_VHOST_OWNER,       1, NULL, OPT_VHOST_OWNER_NUM      },
80 +       {OPT_VHOST_PERM,        1, NULL, OPT_VHOST_PERM_NUM       },
81         {0,                     0, NULL, 0                        }
82  };
83  
84 --- a/lib/librte_eal/common/eal_options.h
85 +++ b/lib/librte_eal/common/eal_options.h
86 @@ -83,6 +83,10 @@ enum {
87         OPT_VMWARE_TSC_MAP_NUM,
88  #define OPT_XEN_DOM0          "xen-dom0"
89         OPT_XEN_DOM0_NUM,
90 +#define OPT_VHOST_OWNER       "vhost-owner"
91 +       OPT_VHOST_OWNER_NUM,
92 +#define OPT_VHOST_PERM        "vhost-perm"
93 +       OPT_VHOST_PERM_NUM,
94         OPT_LONG_MAX_NUM
95  };
96  
97 --- a/lib/librte_eal/common/include/rte_eal.h
98 +++ b/lib/librte_eal/common/include/rte_eal.h
99 @@ -286,6 +286,11 @@ static inline int rte_gettid(void)
100  #define RTE_INIT(func) \
101  static void __attribute__((constructor, used)) func(void)
102  
103 +/**
104 + * Set owner/permissions on sockets if requested on EAL commandline
105 + */
106 +void rte_eal_set_socket_permissions(const char *);
107 +
108  #ifdef __cplusplus
109  }
110  #endif
111 --- a/lib/librte_eal/linuxapp/eal/eal.c
112 +++ b/lib/librte_eal/linuxapp/eal/eal.c
113 @@ -53,6 +53,9 @@
114  #if defined(RTE_ARCH_X86)
115  #include <sys/io.h>
116  #endif
117 +#include <sys/types.h>
118 +#include <pwd.h>
119 +#include <grp.h>
120  
121  #include <rte_common.h>
122  #include <rte_debug.h>
123 @@ -119,6 +122,12 @@ struct lcore_config lcore_config[RTE_MAX
124  /* internal configuration */
125  struct internal_config internal_config;
126  
127 +/* workaround to be able to create the sockets under a certain set of
128 + * owner/permissions as specified to EAL until solved upstream */
129 +static uid_t debian_vhost_sock_uid = (uid_t)-1;
130 +static gid_t debian_vhost_sock_gid = (gid_t)-1;
131 +static mode_t debian_vhost_sock_perm = 0;
132 +
133  /* used by rte_rdtsc() */
134  int rte_cycles_vmware_tsc_map;
135  
136 @@ -356,6 +365,8 @@ eal_usage(const char *prgname)
137                "  --"OPT_CREATE_UIO_DEV"    Create /dev/uioX (usually done by hotplug)\n"
138                "  --"OPT_VFIO_INTR"         Interrupt mode for VFIO (legacy|msi|msix)\n"
139                "  --"OPT_XEN_DOM0"          Support running on Xen dom0 without hugetlbfs\n"
140 +              "  --"OPT_VHOST_OWNER"       Create vhost-user sockets with this owner:group\n"
141 +              "  --"OPT_VHOST_PERM"        Create vhost-user sockets with these permissions\n"
142                "\n");
143         /* Allow the application to print its usage message too if hook is set */
144         if ( rte_application_usage_hook ) {
145 @@ -515,6 +526,121 @@ eal_log_level_parse(int argc, char **arg
146         optarg = old_optarg;
147  }
148  
149 +/* Try to double the size of '*buf', return true
150 + * if successful, and '*sizep' will be updated with
151 + * the new size. Otherwise, return false.  */
152 +static int
153 +enlarge_buffer(char **buf, size_t *sizep)
154 +{
155 +    size_t newsize = *sizep * 2;
156 +
157 +    if (newsize > *sizep) {
158 +        *buf = realloc(*buf, newsize);
159 +        *sizep = newsize;
160 +        return 1;
161 +    }
162 +
163 +    return 0;
164 +}
165 +
166 +static int
167 +get_owners_from_str(const char *user_spec, uid_t *uid, gid_t *gid)
168 +{
169 +       size_t bufsize = 4096;
170 +
171 +       char *pos = strchr(user_spec, ':');
172 +       user_spec += strspn(user_spec, " \t\r\n");
173 +       size_t len = pos ? (size_t)(pos - user_spec) : strlen(user_spec);
174 +
175 +       char *buf = NULL;
176 +       struct passwd pwd, *res;
177 +       int e;
178 +
179 +       buf = malloc(bufsize);
180 +       char *user_search = NULL;
181 +       if (len) {
182 +               user_search = malloc(len + 1);
183 +               memcpy(user_search, user_spec, len);
184 +               user_search[len] = '\0';
185 +               while ((e = getpwnam_r(user_search, &pwd, buf, bufsize, &res)) == ERANGE) {
186 +                       if (!enlarge_buffer(&buf, &bufsize)) {
187 +                               break;
188 +                       }
189 +               }
190 +
191 +               if (e != 0) {
192 +                       RTE_LOG(ERR, EAL,"Failed to retrive user %s's uid (%s), aborting.",
193 +                               user_search, strerror(e));
194 +                       goto release;
195 +               }
196 +               if (res == NULL) {
197 +                       RTE_LOG(ERR, EAL,"user %s not found,  aborting.",
198 +                               user_search);
199 +                       e = -1;
200 +                       goto release;
201 +               }
202 +       } else {
203 +               /* User name is not specified, use current user.  */
204 +               while ((e = getpwuid_r(getuid(), &pwd, buf, bufsize, &res)) == ERANGE) {
205 +                       if (!enlarge_buffer(&buf, &bufsize)) {
206 +                               break;
207 +                       }
208 +               }
209 +
210 +               if (e != 0) {
211 +                       RTE_LOG(ERR, EAL,"Failed to retrive current user's uid "
212 +                               "(%s), aborting.", strerror(e));
213 +                       goto release;
214 +               }
215 +               user_search = strdup(pwd.pw_name);
216 +       }
217 +
218 +       if (uid)
219 +               *uid = pwd.pw_uid;
220 +
221 +       free(buf);
222 +       buf = NULL;
223 +
224 +       if (pos) {
225 +               char *grpstr = pos + 1;
226 +               grpstr += strspn(grpstr, " \t\r\n");
227 +
228 +               if (*grpstr) {
229 +                       struct group grp, *res;
230 +
231 +                       bufsize = 4096;
232 +                       buf = malloc(bufsize);
233 +                       while ((e = getgrnam_r(grpstr, &grp, buf, bufsize, &res))
234 +                                        == ERANGE) {
235 +                               if (!enlarge_buffer(&buf, &bufsize)) {
236 +                                       break;
237 +                               }
238 +                       }
239 +
240 +                       if (e) {
241 +                               RTE_LOG(ERR, EAL,"Failed to get group entry for %s, "
242 +                                       "(%s), aborting.", grpstr,
243 +                                       strerror(e));
244 +                               goto release;
245 +                       }
246 +                       if (res == NULL) {
247 +                               RTE_LOG(ERR, EAL,"Group %s not found, aborting.",
248 +                                       grpstr);
249 +                               e = -1;
250 +                               goto release;
251 +                       }
252 +
253 +                       if (gid)
254 +                               *gid = grp.gr_gid;
255 +               }
256 +       }
257 +
258 + release:
259 +       free(buf);
260 +       free(user_search);
261 +       return e;
262 +}
263 +
264  /* Parse the argument given in the command line of the application */
265  static int
266  eal_parse_args(int argc, char **argv)
267 @@ -611,6 +737,26 @@ eal_parse_args(int argc, char **argv)
268                         internal_config.create_uio_dev = 1;
269                         break;
270  
271 +               case OPT_VHOST_OWNER_NUM:
272 +                       if (get_owners_from_str(optarg, &debian_vhost_sock_uid,
273 +                                                                       &debian_vhost_sock_gid)) {
274 +                               RTE_LOG(ERR, EAL,"vhost-user socket unable to get"
275 +                                       " specified user/group: %s\n", optarg);
276 +                               debian_vhost_sock_uid = (uid_t)-1;
277 +                               debian_vhost_sock_gid = (gid_t)-1;
278 +                       }
279 +                       else {
280 +                               RTE_LOG(INFO, EAL,"socket owner specified as %s (%d:%d)\n",
281 +                                       optarg, debian_vhost_sock_uid, debian_vhost_sock_gid);
282 +                       }
283 +                       break;
284 +
285 +               case OPT_VHOST_PERM_NUM:
286 +                       debian_vhost_sock_perm = (mode_t)strtoul(optarg, NULL, 0);
287 +                       RTE_LOG(INFO, EAL,"socket perm specified as '%#o' from '%s'\n",
288 +                                       debian_vhost_sock_perm, optarg);
289 +                       break;
290 +
291                 default:
292                         if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
293                                 RTE_LOG(ERR, EAL, "Option %c is not supported "
294 @@ -995,3 +1141,47 @@ rte_eal_check_module(const char *module_
295         /* Module has been found */
296         return 1;
297  }
298 +
299 +static void
300 +vhost_set_permissions(const char *vhost_sock_location)
301 +{
302 +       int err = chmod(vhost_sock_location, debian_vhost_sock_perm);
303 +       if (err) {
304 +               RTE_LOG(ERR, EAL,"vhost-user socket cannot set"
305 +                       " permissions to %#o (%s).\n",
306 +                       debian_vhost_sock_perm, strerror(err));
307 +               return;
308 +       }
309 +       RTE_LOG(INFO, EAL,"Socket %s changed permissions"
310 +                       " to %#o\n", vhost_sock_location,
311 +                       debian_vhost_sock_perm);
312 +}
313 +
314 +static void
315 +vhost_set_ownership(const char *vhost_sock_location)
316 +{
317 +       int err = chown(vhost_sock_location, debian_vhost_sock_uid, debian_vhost_sock_gid);
318 +       if (err) {
319 +               RTE_LOG(ERR, EAL,"vhost-user socket unable to set"
320 +                       " ownership to %d:%d (%s).\n",
321 +                       debian_vhost_sock_uid, debian_vhost_sock_gid,
322 +                       strerror(err));
323 +               return;
324 +       }
325 +
326 +       RTE_LOG(INFO, EAL,"Socket %s changed ownership"
327 +                       " to %d:%d.\n", vhost_sock_location,
328 +                       debian_vhost_sock_uid, debian_vhost_sock_gid);
329 +}
330 +
331 +void
332 +rte_eal_set_socket_permissions(const char *path)
333 +{
334 +       if (debian_vhost_sock_perm != 0) {
335 +               vhost_set_permissions(path);
336 +       }
337 +
338 +       if (debian_vhost_sock_uid != (uid_t)-1 || debian_vhost_sock_gid != (gid_t)-1) {
339 +               vhost_set_ownership(path);
340 +       }
341 +}
342 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
343 +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
344 @@ -120,6 +120,7 @@ DPDK_2.2 {
345         rte_keepalive_register_core;
346         rte_xen_dom0_supported;
347         rte_xen_mem_phy2mch;
348 +       rte_eal_set_socket_permissions;
349  
350  } DPDK_2.1;
351  
352 --- a/lib/librte_vhost/socket.c
353 +++ b/lib/librte_vhost/socket.c
354 @@ -98,6 +98,8 @@ struct vhost_user {
355         pthread_mutex_t mutex;
356  };
357  
358 +#include <rte_eal.h>
359 +
360  #define MAX_VIRTIO_BACKLOG 128
361  
362  static void vhost_user_server_new_connection(int fd, void *data, int *remove);
363 @@ -348,6 +350,7 @@ vhost_user_start_server(struct vhost_use
364                 goto err;
365         }
366  
367 +       rte_eal_set_socket_permissions(path);
368         return 0;
369  
370  err: