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