1 /*
2  * Copyright (C) 2011
3  * Author Roger Pau Monne <roger.pau@entel.upc.edu>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; version 2.1 only. with the special
8  * exception on linking described in file LICENSE.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  */
15 
16 #include "libxl_osdeps.h" /* must come before any other headers */
17 
18 #include <sys/resource.h>
19 #include "libxl_internal.h"
20 
21 
22 /* Workarounds for Linux-specific lacks can go here: */
23 
24 #ifndef CLONE_NEWIPC /* Available as of Linux 2.6.19 / glibc 2.8 */
25 # define CLONE_NEWIPC 0x08000000
26 #endif
27 
28 
libxl__try_phy_backend(mode_t st_mode)29 int libxl__try_phy_backend(mode_t st_mode)
30 {
31     if (S_ISBLK(st_mode) || S_ISREG(st_mode)) {
32         return 1;
33     }
34 
35     return 0;
36 }
37 
libxl__devid_to_localdev(libxl__gc * gc,int devid)38 char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
39 {
40     return libxl__devid_to_vdev(gc, devid);
41 }
42 
43 /* Hotplug scripts helpers */
44 
get_hotplug_env(libxl__gc * gc,char * script,libxl__device * dev)45 static char **get_hotplug_env(libxl__gc *gc,
46                               char *script, libxl__device *dev)
47 {
48     const char *type = libxl__device_kind_to_string(dev->backend_kind);
49     char *be_path = libxl__device_backend_path(gc, dev);
50     char **env;
51     int nr = 0;
52 
53     const int arraysize = 15;
54     GCNEW_ARRAY(env, arraysize);
55     env[nr++] = "script";
56     env[nr++] = script;
57     env[nr++] = "XENBUS_TYPE";
58     env[nr++] = (char *) type;
59     env[nr++] = "XENBUS_PATH";
60     env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid, dev->devid);
61     env[nr++] = "XENBUS_BASE_PATH";
62     env[nr++] = "backend";
63     if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) {
64         libxl_nic_type nictype;
65         char *gatewaydev;
66 
67         gatewaydev = libxl__xs_read(gc, XBT_NULL,
68                                     GCSPRINTF("%s/%s", be_path, "gatewaydev"));
69         env[nr++] = "netdev";
70         env[nr++] = gatewaydev ? : "";
71 
72         if (libxl__nic_type(gc, dev, &nictype)) {
73             LOGD(ERROR, dev->domid, "unable to get nictype");
74             return NULL;
75         }
76         switch (nictype) {
77         case LIBXL_NIC_TYPE_VIF_IOEMU:
78             env[nr++] = "INTERFACE";
79             env[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
80                                                     dev->devid,
81                                                     LIBXL_NIC_TYPE_VIF_IOEMU);
82             /*
83              * We need to fall through because for PV_IOEMU nic types we need
84              * to execute both the vif and the tap hotplug script, and we
85              * don't know which one we are executing in this call, so provide
86              * both env variables.
87              */
88         case LIBXL_NIC_TYPE_VIF:
89             env[nr++] = "vif";
90             env[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
91                                                     dev->devid,
92                                                     LIBXL_NIC_TYPE_VIF);
93             break;
94         default:
95             return NULL;
96         }
97     }
98 
99     env[nr++] = NULL;
100     assert(nr <= arraysize);
101 
102     return env;
103 }
104 
105 /* Hotplug scripts caller functions */
106 
libxl__hotplug_nic(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action,int num_exec)107 static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev,
108                                char ***args, char ***env,
109                                libxl__device_action action, int num_exec)
110 {
111     char *be_path = libxl__device_backend_path(gc, dev);
112     char *script;
113     int nr = 0, rc = 0;
114     libxl_nic_type nictype;
115 
116     script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path,
117                                                              "script"));
118     if (!script) {
119         LOGED(ERROR, dev->domid,
120               "unable to read script from %s", be_path);
121         rc = ERROR_FAIL;
122         goto out;
123     }
124 
125     rc = libxl__nic_type(gc, dev, &nictype);
126     if (rc) {
127         LOGD(ERROR, dev->domid, "error when fetching nic type");
128         rc = ERROR_FAIL;
129         goto out;
130     }
131     if (nictype == LIBXL_NIC_TYPE_VIF && num_exec != 0) {
132         rc = 0;
133         goto out;
134     }
135 
136     *env = get_hotplug_env(gc, script, dev);
137     if (!*env) {
138         rc = ERROR_FAIL;
139         goto out;
140     }
141 
142     const int arraysize = 4;
143     GCNEW_ARRAY(*args, arraysize);
144     (*args)[nr++] = script;
145 
146     if (nictype == LIBXL_NIC_TYPE_VIF_IOEMU && num_exec) {
147         (*args)[nr++] = (char *) libxl__device_action_to_string(action);
148         (*args)[nr++] = "type_if=tap";
149         (*args)[nr++] = NULL;
150     } else {
151         (*args)[nr++] = action == LIBXL__DEVICE_ACTION_ADD ? "online" :
152                                                              "offline";
153         (*args)[nr++] = "type_if=vif";
154         (*args)[nr++] = NULL;
155     }
156     assert(nr == arraysize);
157     rc = 1;
158 
159 out:
160     return rc;
161 }
162 
libxl__hotplug_disk(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action)163 static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
164                                char ***args, char ***env,
165                                libxl__device_action action)
166 {
167     char *be_path = libxl__device_backend_path(gc, dev);
168     char *script;
169     int nr = 0, rc = 0;
170 
171     script = libxl__xs_read(gc, XBT_NULL,
172                             GCSPRINTF("%s/%s", be_path, "script"));
173     if (!script) {
174         LOGEVD(ERROR, errno, dev->domid,
175                "unable to read script from %s", be_path);
176         rc = ERROR_FAIL;
177         goto error;
178     }
179 
180     *env = get_hotplug_env(gc, script, dev);
181     if (!*env) {
182         LOGD(ERROR, dev->domid, "Failed to get hotplug environment");
183         rc = ERROR_FAIL;
184         goto error;
185     }
186 
187     const int arraysize = 3;
188     GCNEW_ARRAY(*args, arraysize);
189     (*args)[nr++] = script;
190     (*args)[nr++] = (char *) libxl__device_action_to_string(action);
191     (*args)[nr++] = NULL;
192     assert(nr == arraysize);
193 
194     LOGD(DEBUG, dev->domid, "Args and environment ready");
195     rc = 1;
196 
197 error:
198     return rc;
199 }
200 
libxl__get_hotplug_script_info(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action,int num_exec)201 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
202                                    char ***args, char ***env,
203                                    libxl__device_action action,
204                                    int num_exec)
205 {
206     int rc;
207 
208     switch (dev->backend_kind) {
209     case LIBXL__DEVICE_KIND_VBD:
210         if (num_exec != 0) {
211             LOGD(DEBUG, dev->domid,
212                  "num_exec %d, not running hotplug scripts", num_exec);
213             rc = 0;
214             goto out;
215         }
216         rc = libxl__hotplug_disk(gc, dev, args, env, action);
217         break;
218     case LIBXL__DEVICE_KIND_VIF:
219         /*
220          * If domain has a stubdom we don't have to execute hotplug scripts
221          * for emulated interfaces
222          */
223         if ((num_exec > 1) ||
224             (libxl_get_stubdom_id(CTX, dev->domid) && num_exec)) {
225             LOGD(DEBUG, dev->domid,
226                  "num_exec %d, not running hotplug scripts", num_exec);
227             rc = 0;
228             goto out;
229         }
230         rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
231         break;
232     default:
233         /* No need to execute any hotplug scripts */
234         LOGD(DEBUG, dev->domid,
235              "backend_kind %d, no need to execute scripts", dev->backend_kind);
236         rc = 0;
237         break;
238     }
239 
240 out:
241     return rc;
242 }
243 
libxl__default_device_model(libxl__gc * gc)244 libxl_device_model_version libxl__default_device_model(libxl__gc *gc)
245 {
246     return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
247 }
248 
libxl__pci_numdevs(libxl__gc * gc)249 int libxl__pci_numdevs(libxl__gc *gc)
250 {
251     DIR *dir;
252     struct dirent *entry;
253     int num_devs = 0;
254 
255     dir = opendir("/sys/bus/pci/devices");
256     if (!dir) {
257         LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
258         return ERROR_FAIL;
259     }
260 
261     while ((entry = readdir(dir))) {
262         if (entry->d_name[0] == '.')
263             continue;
264         num_devs++;
265     }
266     closedir(dir);
267 
268     return num_devs;
269 }
270 
libxl__pci_topology_init(libxl__gc * gc,physdev_pci_device_t * devs,int num_devs)271 int libxl__pci_topology_init(libxl__gc *gc,
272                              physdev_pci_device_t *devs,
273                              int num_devs)
274 {
275 
276     DIR *dir;
277     struct dirent *entry;
278     int i, err = 0;
279 
280     dir = opendir("/sys/bus/pci/devices");
281     if (!dir) {
282         LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
283         return ERROR_FAIL;
284     }
285 
286     i = 0;
287     while ((entry = readdir(dir))) {
288         unsigned int dom, bus, dev, func;
289 
290         if (entry->d_name[0] == '.')
291             continue;
292 
293         if (i == num_devs) {
294             LOG(ERROR, "Too many devices");
295             err = ERROR_FAIL;
296             errno = -ENOSPC;
297             goto out;
298         }
299 
300         if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4) {
301             LOGE(ERROR, "Error processing /sys/bus/pci/devices");
302             err = ERROR_FAIL;
303             goto out;
304         }
305 
306         devs[i].seg = dom;
307         devs[i].bus = bus;
308         devs[i].devfn = ((dev & 0x1f) << 3) | (func & 7);
309 
310         i++;
311     }
312 
313  out:
314     closedir(dir);
315 
316     return err;
317 }
318 
319 static struct {
320     int resource;
321     rlim_t limit;
322 } rlimits[] = {
323 #define RLIMIT_ENTRY(r, l) \
324     { .resource = r, .limit = l }
325     /* Big enough for log files, not big enough for a DoS */
326     RLIMIT_ENTRY(RLIMIT_FSIZE,    256*1024),
327 
328     /* Shouldn't need any of these */
329     RLIMIT_ENTRY(RLIMIT_CORE,     0),
330     RLIMIT_ENTRY(RLIMIT_MSGQUEUE, 0),
331     RLIMIT_ENTRY(RLIMIT_LOCKS,    0),
332     RLIMIT_ENTRY(RLIMIT_MEMLOCK,  0),
333 
334     /* End-of-list marker */
335     RLIMIT_ENTRY(RLIMIT_NLIMITS,  0),
336 #undef RLIMIT_ENTRY
337 };
338 
libxl__local_dm_preexec_restrict(libxl__gc * gc)339 int libxl__local_dm_preexec_restrict(libxl__gc *gc)
340 {
341     int r;
342     unsigned i;
343 
344     /* Unshare mount and IPC namespaces.  These are unused by QEMU. */
345     r = unshare(CLONE_NEWNS | CLONE_NEWIPC);
346     if (r) {
347         LOGE(ERROR, "libxl: unshare Mount and IPC namespace failed");
348         return ERROR_FAIL;
349     }
350 
351     /* Set various "easy" rlimits */
352     for (i = 0; rlimits[i].resource != RLIMIT_NLIMITS; i++) {
353         struct rlimit rlim;
354 
355         rlim.rlim_cur = rlim.rlim_max = rlimits[i].limit;
356 
357         r = setrlimit(rlimits[i].resource, &rlim);
358         if (r < 0) {
359             LOGE(ERROR, "Setting rlimit %d to %llu failed\n",
360                                   rlimits[i].resource,
361                                   (unsigned long long)rlimits[i].limit);
362             return ERROR_FAIL;
363         }
364     }
365 
366     return 0;
367 }
368 
369 /*
370  * Local variables:
371  * mode: C
372  * c-basic-offset: 4
373  * indent-tabs-mode: nil
374  * End:
375  */
376