debuggers.hg

view tools/libxl/libxl_create.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents 8b6e7f43683e
children c5a7a40cc4f4
line source
1 /*
2 * Copyright (C) 2010 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
5 * Author Gianni Tedesco <gianni.tedesco@citrix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; version 2.1 only. with the special
10 * exception on linking described in file LICENSE.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 */
18 #include "libxl_osdeps.h"
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <xenctrl.h>
26 #include <xc_dom.h>
27 #include <xenguest.h>
28 #include "libxl.h"
29 #include "libxl_utils.h"
30 #include "libxl_internal.h"
31 #include "flexarray.h"
33 void libxl_domain_config_destroy(libxl_domain_config *d_config)
34 {
35 int i;
37 for (i=0; i<d_config->num_disks; i++)
38 libxl_device_disk_destroy(&d_config->disks[i]);
39 free(d_config->disks);
41 for (i=0; i<d_config->num_vifs; i++)
42 libxl_device_nic_destroy(&d_config->vifs[i]);
43 free(d_config->vifs);
45 for (i=0; i<d_config->num_vif2s; i++)
46 libxl_device_net2_destroy(&d_config->vif2s[i]);
47 free(d_config->vif2s);
49 for (i=0; i<d_config->num_pcidevs; i++)
50 libxl_device_pci_destroy(&d_config->pcidevs[i]);
51 free(d_config->pcidevs);
53 for (i=0; i<d_config->num_vfbs; i++)
54 libxl_device_vfb_destroy(&d_config->vfbs[i]);
55 free(d_config->vfbs);
57 for (i=0; i<d_config->num_vkbs; i++)
58 libxl_device_vkb_destroy(&d_config->vkbs[i]);
59 free(d_config->vkbs);
61 libxl_domain_create_info_destroy(&d_config->c_info);
62 libxl_domain_build_info_destroy(&d_config->b_info);
63 libxl_device_model_info_destroy(&d_config->dm_info);
64 }
66 void libxl_init_create_info(libxl_domain_create_info *c_info)
67 {
68 memset(c_info, '\0', sizeof(*c_info));
69 c_info->xsdata = NULL;
70 c_info->platformdata = NULL;
71 c_info->hap = 1;
72 c_info->hvm = 1;
73 c_info->oos = 1;
74 c_info->ssidref = 0;
75 c_info->poolid = 0;
76 }
78 void libxl_init_build_info(libxl_domain_build_info *b_info, libxl_domain_create_info *c_info)
79 {
80 memset(b_info, '\0', sizeof(*b_info));
81 b_info->max_vcpus = 1;
82 b_info->cur_vcpus = 1;
83 b_info->max_memkb = 32 * 1024;
84 b_info->target_memkb = b_info->max_memkb;
85 b_info->disable_migrate = 0;
86 b_info->cpuid = NULL;
87 b_info->shadow_memkb = 0;
88 if (c_info->hvm) {
89 b_info->video_memkb = 8 * 1024;
90 b_info->kernel.path = strdup("hvmloader");
91 b_info->hvm = 1;
92 b_info->u.hvm.pae = 1;
93 b_info->u.hvm.apic = 1;
94 b_info->u.hvm.acpi = 1;
95 b_info->u.hvm.nx = 1;
96 b_info->u.hvm.viridian = 0;
97 b_info->u.hvm.hpet = 1;
98 b_info->u.hvm.vpt_align = 1;
99 b_info->u.hvm.timer_mode = 1;
100 } else {
101 b_info->u.pv.slack_memkb = 8 * 1024;
102 }
103 }
105 void libxl_init_dm_info(libxl_device_model_info *dm_info,
106 libxl_domain_create_info *c_info, libxl_domain_build_info *b_info)
107 {
108 memset(dm_info, '\0', sizeof(*dm_info));
110 libxl_uuid_generate(&dm_info->uuid);
112 dm_info->dom_name = strdup(c_info->name);
113 dm_info->device_model = strdup("qemu-dm");
114 dm_info->target_ram = libxl__sizekb_to_mb(b_info->target_memkb);
115 dm_info->videoram = libxl__sizekb_to_mb(b_info->video_memkb);
116 dm_info->apic = b_info->u.hvm.apic;
117 dm_info->vcpus = b_info->max_vcpus;
118 dm_info->vcpu_avail = b_info->cur_vcpus;
120 dm_info->stdvga = 0;
121 dm_info->vnc = 1;
122 dm_info->vnclisten = strdup("127.0.0.1");
123 dm_info->vncdisplay = 0;
124 dm_info->vncunused = 1;
125 dm_info->keymap = NULL;
126 dm_info->sdl = 0;
127 dm_info->opengl = 0;
128 dm_info->nographic = 0;
129 dm_info->serial = NULL;
130 dm_info->boot = strdup("cda");
131 dm_info->usb = 0;
132 dm_info->usbdevice = NULL;
133 dm_info->xen_platform_pci = 1;
134 }
136 static int init_console_info(libxl_device_console *console, int dev_num, libxl_domain_build_state *state)
137 {
138 memset(console, 0x00, sizeof(libxl_device_console));
139 console->devid = dev_num;
140 console->consback = LIBXL_CONSBACK_XENCONSOLED;
141 console->output = strdup("pty");
142 if ( NULL == console->output )
143 return ERROR_NOMEM;
144 if (state)
145 console->build_state = state;
146 return 0;
147 }
149 int libxl__domain_build(libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid, libxl_domain_build_state *state)
150 {
151 libxl__gc gc = LIBXL_INIT_GC(ctx);
152 char **vments = NULL, **localents = NULL;
153 struct timeval start_time;
154 int i, ret;
156 ret = libxl__build_pre(ctx, domid, info, state);
157 if (ret)
158 goto out;
160 gettimeofday(&start_time, NULL);
162 if (info->hvm) {
163 ret = libxl__build_hvm(ctx, domid, info, state);
164 if (ret)
165 goto out;
167 vments = libxl__calloc(&gc, 7, sizeof(char *));
168 vments[0] = "rtc/timeoffset";
169 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
170 vments[2] = "image/ostype";
171 vments[3] = "hvm";
172 vments[4] = "start_time";
173 vments[5] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
174 } else {
175 ret = libxl__build_pv(ctx, domid, info, state);
176 if (ret)
177 goto out;
179 vments = libxl__calloc(&gc, 11, sizeof(char *));
180 i = 0;
181 vments[i++] = "image/ostype";
182 vments[i++] = "linux";
183 vments[i++] = "image/kernel";
184 vments[i++] = (char*) info->kernel.path;
185 vments[i++] = "start_time";
186 vments[i++] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
187 if (info->u.pv.ramdisk.path) {
188 vments[i++] = "image/ramdisk";
189 vments[i++] = (char*) info->u.pv.ramdisk.path;
190 }
191 if (info->u.pv.cmdline) {
192 vments[i++] = "image/cmdline";
193 vments[i++] = (char*) info->u.pv.cmdline;
194 }
195 }
196 ret = libxl__build_post(ctx, domid, info, state, vments, localents);
197 out:
198 libxl__file_reference_unmap(&info->kernel);
199 if (!info->hvm)
200 libxl__file_reference_unmap(&info->u.pv.ramdisk);
202 libxl__free_all(&gc);
203 return ret;
204 }
206 static int domain_restore(libxl_ctx *ctx, libxl_domain_build_info *info,
207 uint32_t domid, int fd, libxl_domain_build_state *state,
208 libxl_device_model_info *dm_info)
209 {
210 libxl__gc gc = LIBXL_INIT_GC(ctx);
211 char **vments = NULL, **localents = NULL;
212 struct timeval start_time;
213 int i, ret, esave, flags;
215 ret = libxl__build_pre(ctx, domid, info, state);
216 if (ret)
217 goto out;
219 ret = libxl__domain_restore_common(ctx, domid, info, state, fd);
220 if (ret)
221 goto out;
223 gettimeofday(&start_time, NULL);
225 if (info->hvm) {
226 vments = libxl__calloc(&gc, 7, sizeof(char *));
227 vments[0] = "rtc/timeoffset";
228 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
229 vments[2] = "image/ostype";
230 vments[3] = "hvm";
231 vments[4] = "start_time";
232 vments[5] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
233 } else {
234 vments = libxl__calloc(&gc, 11, sizeof(char *));
235 i = 0;
236 vments[i++] = "image/ostype";
237 vments[i++] = "linux";
238 vments[i++] = "image/kernel";
239 vments[i++] = (char*) info->kernel.path;
240 vments[i++] = "start_time";
241 vments[i++] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
242 if (info->u.pv.ramdisk.path) {
243 vments[i++] = "image/ramdisk";
244 vments[i++] = (char*) info->u.pv.ramdisk.path;
245 }
246 if (info->u.pv.cmdline) {
247 vments[i++] = "image/cmdline";
248 vments[i++] = (char*) info->u.pv.cmdline;
249 }
250 }
251 ret = libxl__build_post(ctx, domid, info, state, vments, localents);
252 if (ret)
253 goto out;
255 dm_info->saved_state = NULL;
256 if (info->hvm) {
257 ret = asprintf(&dm_info->saved_state,
258 XC_DEVICE_MODEL_RESTORE_FILE".%d", domid);
259 ret = (ret < 0) ? ERROR_FAIL : 0;
260 }
262 out:
263 libxl__file_reference_unmap(&info->kernel);
264 if (!info->hvm)
265 libxl__file_reference_unmap(&info->u.pv.ramdisk);
267 esave = errno;
269 flags = fcntl(fd, F_GETFL);
270 if (flags == -1) {
271 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to get flags on restore fd");
272 } else {
273 flags &= ~O_NONBLOCK;
274 if (fcntl(fd, F_SETFL, flags) == -1)
275 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to put restore fd"
276 " back to blocking mode");
277 }
279 errno = esave;
280 libxl__free_all(&gc);
281 return ret;
282 }
284 int libxl__domain_make(libxl_ctx *ctx, libxl_domain_create_info *info,
285 uint32_t *domid)
286 {
287 libxl__gc gc = LIBXL_INIT_GC(ctx);
288 int flags, ret, i, rc;
289 char *uuid_string;
290 char *rw_paths[] = { "device", "device/suspend/event-channel" , "data"};
291 char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
292 "control", "attr", "messages" };
293 char *dom_path, *vm_path;
294 struct xs_permissions roperm[2];
295 struct xs_permissions rwperm[1];
296 xs_transaction_t t;
297 xen_domain_handle_t handle;
299 uuid_string = libxl__uuid2string(&gc, info->uuid);
300 if (!uuid_string) {
301 libxl__free_all(&gc);
302 return ERROR_NOMEM;
303 }
305 flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
306 flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
307 flags |= info->oos ? 0 : XEN_DOMCTL_CDF_oos_off;
308 *domid = -1;
310 /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
311 libxl_uuid_copy((libxl_uuid *)handle, &info->uuid);
313 ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
314 if (ret < 0) {
315 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain creation fail");
316 libxl__free_all(&gc);
317 return ERROR_FAIL;
318 }
320 ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid);
321 if (ret < 0) {
322 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain move fail");
323 libxl__free_all(&gc);
324 return ERROR_FAIL;
325 }
327 dom_path = libxl__xs_get_dompath(&gc, *domid);
328 if (!dom_path) {
329 libxl__free_all(&gc);
330 return ERROR_FAIL;
331 }
333 vm_path = libxl__sprintf(&gc, "/vm/%s", uuid_string);
334 if (!vm_path) {
335 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths");
336 libxl__free_all(&gc);
337 return ERROR_FAIL;
338 }
340 roperm[0].id = 0;
341 roperm[0].perms = XS_PERM_NONE;
342 roperm[1].id = *domid;
343 roperm[1].perms = XS_PERM_READ;
344 rwperm[0].id = *domid;
345 rwperm[0].perms = XS_PERM_NONE;
347 retry_transaction:
348 t = xs_transaction_start(ctx->xsh);
349 xs_rm(ctx->xsh, t, dom_path);
350 xs_mkdir(ctx->xsh, t, dom_path);
351 xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
353 xs_rm(ctx->xsh, t, vm_path);
354 xs_mkdir(ctx->xsh, t, vm_path);
355 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
357 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/vm", dom_path), vm_path, strlen(vm_path));
358 rc = libxl_domain_rename(ctx, *domid, 0, info->name, t);
359 if (rc) {
360 libxl__free_all(&gc);
361 return rc;
362 }
364 for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
365 char *path = libxl__sprintf(&gc, "%s/%s", dom_path, rw_paths[i]);
366 xs_mkdir(ctx->xsh, t, path);
367 xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
368 }
369 for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
370 char *path = libxl__sprintf(&gc, "%s/%s", dom_path, ro_paths[i]);
371 xs_mkdir(ctx->xsh, t, path);
372 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
373 }
375 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
376 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/name", vm_path), info->name, strlen(info->name));
377 if (info->poolname)
378 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/pool_name", vm_path), info->poolname, strlen(info->poolname));
380 libxl__xs_writev(&gc, t, dom_path, info->xsdata);
381 libxl__xs_writev(&gc, t, libxl__sprintf(&gc, "%s/platform", dom_path), info->platformdata);
383 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
384 if (!xs_transaction_end(ctx->xsh, t, 0))
385 if (errno == EAGAIN)
386 goto retry_transaction;
388 libxl__free_all(&gc);
389 return 0;
390 }
392 static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config,
393 libxl_console_ready cb, void *priv,
394 uint32_t *domid_out, int restore_fd)
395 {
396 libxl__device_model_starting *dm_starting = 0;
397 libxl_device_model_info *dm_info = &d_config->dm_info;
398 libxl_domain_build_state state;
399 uint32_t domid;
400 int i, ret;
402 domid = 0;
404 ret = libxl__domain_make(ctx, &d_config->c_info, &domid);
405 if (ret) {
406 fprintf(stderr, "cannot make domain: %d\n", ret);
407 ret = ERROR_FAIL;
408 goto error_out;
409 }
411 if ( !d_config->c_info.hvm && cb ) {
412 if ( (*cb)(ctx, domid, priv) )
413 goto error_out;
414 }
416 if ( restore_fd < 0 ) {
417 ret = libxl_run_bootloader(ctx, &d_config->b_info, d_config->num_disks > 0 ? &d_config->disks[0] : NULL, domid);
418 if (ret) {
419 fprintf(stderr, "failed to run bootloader: %d\n", ret);
420 goto error_out;
421 }
422 }
424 if ( restore_fd >= 0 ) {
425 ret = domain_restore(ctx, &d_config->b_info, domid, restore_fd, &state, dm_info);
426 } else {
427 if (dm_info->saved_state) {
428 free(dm_info->saved_state);
429 dm_info->saved_state = NULL;
430 }
431 ret = libxl__domain_build(ctx, &d_config->b_info, domid, &state);
432 }
434 if (ret) {
435 fprintf(stderr, "cannot (re-)build domain: %d\n", ret);
436 ret = ERROR_FAIL;
437 goto error_out;
438 }
440 for (i = 0; i < d_config->num_disks; i++) {
441 d_config->disks[i].domid = domid;
442 ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i]);
443 if (ret) {
444 fprintf(stderr, "cannot add disk %d to domain: %d\n", i, ret);
445 ret = ERROR_FAIL;
446 goto error_out;
447 }
448 }
449 for (i = 0; i < d_config->num_vifs; i++) {
450 d_config->vifs[i].domid = domid;
451 ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
452 if (ret) {
453 fprintf(stderr, "cannot add nic %d to domain: %d\n", i, ret);
454 ret = ERROR_FAIL;
455 goto error_out;
456 }
457 }
458 if (!d_config->c_info.hvm) {
459 for (i = 0; i < d_config->num_vif2s; i++) {
460 d_config->vif2s[i].domid = domid;
461 ret = libxl_device_net2_add(ctx, domid, &d_config->vif2s[i]);
462 if (ret) {
463 fprintf(stderr, "cannot add net2 %d to domain: %d\n", i, ret);
464 ret = ERROR_FAIL;
465 goto error_out;
466 }
467 }
468 }
469 if (d_config->c_info.hvm) {
470 libxl_device_console console;
472 ret = init_console_info(&console, 0, &state);
473 if ( ret )
474 goto error_out;
475 console.domid = domid;
476 libxl_device_console_add(ctx, domid, &console);
477 libxl_device_console_destroy(&console);
479 dm_info->domid = domid;
480 ret = libxl__create_device_model(ctx, dm_info,
481 d_config->disks, d_config->num_disks,
482 d_config->vifs, d_config->num_vifs,
483 &dm_starting);
484 if (ret < 0) {
485 fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: libxl__create_device_model\n",
486 __FILE__,__LINE__, ret);
487 goto error_out;
488 }
489 } else {
490 int need_qemu = 0;
491 libxl_device_console console;
493 for (i = 0; i < d_config->num_vfbs; i++) {
494 d_config->vfbs[i].domid = domid;
495 libxl_device_vfb_add(ctx, domid, &d_config->vfbs[i]);
496 d_config->vkbs[i].domid = domid;
497 libxl_device_vkb_add(ctx, domid, &d_config->vkbs[i]);
498 }
500 ret = init_console_info(&console, 0, &state);
501 if ( ret )
502 goto error_out;
503 console.domid = domid;
505 need_qemu = libxl__need_xenpv_qemu(ctx, 1, &console,
506 d_config->num_vfbs, d_config->vfbs,
507 d_config->num_disks, &d_config->disks[0]);
509 if (need_qemu)
510 console.consback = LIBXL_CONSBACK_IOEMU;
512 libxl_device_console_add(ctx, domid, &console);
513 libxl_device_console_destroy(&console);
515 if (need_qemu)
516 libxl__create_xenpv_qemu(ctx, domid, d_config->vfbs, &dm_starting);
517 }
519 if (dm_starting) {
520 ret = libxl__confirm_device_model_startup(ctx, dm_starting);
521 if (ret < 0) {
522 fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: libxl__confirm_device_model_startup\n",
523 __FILE__,__LINE__, ret);
524 goto error_out;
525 }
526 }
528 for (i = 0; i < d_config->num_pcidevs; i++)
529 libxl_device_pci_add(ctx, domid, &d_config->pcidevs[i]);
531 if ( d_config->c_info.hvm && cb ) {
532 if ( (*cb)(ctx, domid, priv) )
533 goto error_out;
534 }
536 *domid_out = domid;
537 return 0;
539 error_out:
540 if (domid)
541 libxl_domain_destroy(ctx, domid, 0);
543 return ret;
544 }
545 int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config,
546 libxl_console_ready cb, void *priv, uint32_t *domid)
547 {
548 return do_domain_create(ctx, d_config, cb, priv, domid, -1);
549 }
551 int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
552 libxl_console_ready cb, void *priv, uint32_t *domid, int restore_fd)
553 {
554 return do_domain_create(ctx, d_config, cb, priv, domid, restore_fd);
555 }