If defining a VM without any <seclabel> element present, the new verification code will crash as it deferences NULL, so we just need to skip over that. Second, if one does a roundtrip of a live VM config virsh dumpxml foo > foo.xml virsh define foo.xml and then stop and start the guest, it will now fail complaining that the security label is already defined. This is because the XML parser is mistakenly parsing the 'model' attribute even for VMs whose label is defined to be dynamic. This then exposed anothe bug in the qemudStartVMDaemon() method where it would not properly cleanup after a failed launch, failing to reset the dynamic allocated security label, and also failing to close a logfil file descriptor. This patch fixes all of these problems Daniel Index: src/domain_conf.c =================================================================== RCS file: /data/cvs/libvirt/src/domain_conf.c,v retrieving revision 1.74 diff -u -p -r1.74 domain_conf.c --- src/domain_conf.c 3 Apr 2009 10:55:51 -0000 1.74 +++ src/domain_conf.c 3 Apr 2009 12:14:54 -0000 @@ -1859,15 +1859,6 @@ virSecurityLabelDefParseXML(virConnectPt if (virXPathNode(conn, "./seclabel", ctxt) == NULL) return 0; - p = virXPathStringLimit(conn, "string(./seclabel/@model)", - VIR_SECURITY_MODEL_BUFLEN-1, ctxt); - if (p == NULL) { - virDomainReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("missing security model")); - goto error; - } - def->seclabel.model = p; - p = virXPathStringLimit(conn, "string(./seclabel/@type)", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { @@ -1888,6 +1879,14 @@ virSecurityLabelDefParseXML(virConnectPt */ if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC || !(flags & VIR_DOMAIN_XML_INACTIVE)) { + p = virXPathStringLimit(conn, "string(./seclabel/@model)", + VIR_SECURITY_MODEL_BUFLEN-1, ctxt); + if (p == NULL) { + virDomainReportError(conn, VIR_ERR_XML_ERROR, + "%s", _("missing security model")); + goto error; + } + def->seclabel.model = p; p = virXPathStringLimit(conn, "string(./seclabel/label[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); @@ -1905,8 +1904,11 @@ virSecurityLabelDefParseXML(virConnectPt !(flags & VIR_DOMAIN_XML_INACTIVE)) { p = virXPathStringLimit(conn, "string(./seclabel/imagelabel[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); - if (p == NULL) + if (p == NULL) { + virDomainReportError(conn, VIR_ERR_XML_ERROR, + _("security imagelabel is missing")); goto error; + } def->seclabel.imagelabel = p; } Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.224 diff -u -p -r1.224 qemu_driver.c --- src/qemu_driver.c 3 Apr 2009 10:55:51 -0000 1.224 +++ src/qemu_driver.c 3 Apr 2009 12:14:54 -0000 @@ -332,7 +332,7 @@ qemudReconnectVMs(struct qemud_driver *d } if ((vm->logfile = qemudLogFD(NULL, driver->logDir, vm->def->name)) < 0) - return -1; + goto next_error; if (vm->def->id >= driver->nextvmid) driver->nextvmid = vm->def->id + 1; @@ -344,9 +344,12 @@ next_error: /* we failed to reconnect the vm so remove it's traces */ vm->def->id = -1; qemudRemoveDomainStatus(NULL, driver, vm); - virDomainDefFree(vm->def); - vm->def = vm->newDef; - vm->newDef = NULL; + /* Restore orignal def, if we'd loaded a live one */ + if (vm->newDef) { + virDomainDefFree(vm->def); + vm->def = vm->newDef; + vm->newDef = NULL; + } next: virDomainObjUnlock(vm); if (status) @@ -1319,14 +1322,6 @@ static int qemudStartVMDaemon(virConnect hookData.vm = vm; hookData.driver = driver; - /* If you are using a SecurityDriver with dynamic labelling, - then generate a security label for isolation */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && - driver->securityDriver && - driver->securityDriver->domainGenSecurityLabel && - driver->securityDriver->domainGenSecurityLabel(conn, vm) < 0) - return -1; - FD_ZERO(&keepfd); if (virDomainIsActive(vm)) { @@ -1335,6 +1330,14 @@ static int qemudStartVMDaemon(virConnect return -1; } + /* If you are using a SecurityDriver with dynamic labelling, + then generate a security label for isolation */ + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && + driver->securityDriver && + driver->securityDriver->domainGenSecurityLabel && + driver->securityDriver->domainGenSecurityLabel(conn, vm) < 0) + return -1; + if (vm->def->graphics && vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && vm->def->graphics->data.vnc.autoport) { @@ -1342,7 +1345,7 @@ static int qemudStartVMDaemon(virConnect if (port < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to find an unused VNC port")); - return -1; + goto cleanup; } vm->def->graphics->data.vnc.port = port; } @@ -1351,17 +1354,17 @@ static int qemudStartVMDaemon(virConnect virReportSystemError(conn, errno, _("cannot create log directory %s"), driver->logDir); - return -1; + goto cleanup; } if((vm->logfile = qemudLogFD(conn, driver->logDir, vm->def->name)) < 0) - return -1; + goto cleanup; emulator = vm->def->emulator; if (!emulator) emulator = virDomainDefDefaultEmulator(conn, vm->def, driver->caps); if (!emulator) - return -1; + goto cleanup; /* Make sure the binary we are about to try exec'ing exists. * Technically we could catch the exec() failure, but that's @@ -1371,7 +1374,7 @@ static int qemudStartVMDaemon(virConnect virReportSystemError(conn, errno, _("Cannot find QEMU binary %s"), emulator); - return -1; + goto cleanup; } if (qemudExtractVersionInfo(emulator, @@ -1380,21 +1383,17 @@ static int qemudStartVMDaemon(virConnect qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Cannot determine QEMU argv syntax %s"), emulator); - return -1; + goto cleanup; } if (qemuPrepareHostDevices(conn, vm->def) < 0) - return -1; + goto cleanup; vm->def->id = driver->nextvmid++; if (qemudBuildCommandLine(conn, driver, vm, qemuCmdFlags, &argv, &progenv, - &tapfds, &ntapfds, migrateFrom) < 0) { - close(vm->logfile); - vm->def->id = -1; - vm->logfile = -1; - return -1; - } + &tapfds, &ntapfds, migrateFrom) < 0) + goto cleanup; tmp = progenv; while (*tmp) { @@ -1457,12 +1456,8 @@ static int qemudStartVMDaemon(virConnect "%s", _("Unable to daemonize QEMU process")); ret = -1; } - } - - if (ret == 0) { vm->state = migrateFrom ? VIR_DOMAIN_PAUSED : VIR_DOMAIN_RUNNING; - } else - vm->def->id = -1; + } for (i = 0 ; argv[i] ; i++) VIR_FREE(argv[i]); @@ -1479,19 +1474,38 @@ static int qemudStartVMDaemon(virConnect VIR_FREE(tapfds); } - if (ret == 0) { - if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) || - (qemudDetectVcpuPIDs(conn, vm) < 0) || - (qemudInitCpus(conn, vm, migrateFrom) < 0) || - (qemudInitPasswords(conn, driver, vm) < 0) || - (qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) || - (qemudSaveDomainStatus(conn, qemu_driver, vm) < 0)) { - qemudShutdownVMDaemon(conn, driver, vm); - return -1; - } + if (ret == -1) + goto cleanup; + + if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) || + (qemudDetectVcpuPIDs(conn, vm) < 0) || + (qemudInitCpus(conn, vm, migrateFrom) < 0) || + (qemudInitPasswords(conn, driver, vm) < 0) || + (qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) || + (qemudSaveDomainStatus(conn, qemu_driver, vm) < 0)) { + qemudShutdownVMDaemon(conn, driver, vm); + ret = -1; + /* No need for 'goto cleanup' now since qemudShutdownVMDaemon does enough */ } return ret; + +cleanup: + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabel.model); + VIR_FREE(vm->def->seclabel.label); + VIR_FREE(vm->def->seclabel.imagelabel); + } + if (vm->def->graphics && + vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && + vm->def->graphics->data.vnc.autoport) + vm->def->graphics->data.vnc.port = -1; + if (vm->logfile != -1) { + close(vm->logfile); + vm->logfile = -1; + } + vm->def->id = -1; + return -1; } Index: src/security.c =================================================================== RCS file: /data/cvs/libvirt/src/security.c,v retrieving revision 1.3 diff -u -p -r1.3 security.c --- src/security.c 3 Apr 2009 10:55:51 -0000 1.3 +++ src/security.c 3 Apr 2009 12:14:54 -0000 @@ -33,7 +33,8 @@ virSecurityDriverVerify(virConnectPtr co unsigned int i; const virSecurityLabelDefPtr secdef = &def->seclabel; - if (STREQ(secdef->model, "none")) + if (!secdef->model || + STREQ(secdef->model, "none")) return 0; for (i = 0; security_drivers[i] != NULL ; i++) { @@ -42,7 +43,7 @@ virSecurityDriverVerify(virConnectPtr co } } virSecurityReportError(conn, VIR_ERR_XML_ERROR, - _("invalid security model")); + _("invalid security model '%s'"), secdef->model); return -1; } Index: src/security_selinux.c =================================================================== RCS file: /data/cvs/libvirt/src/security_selinux.c,v retrieving revision 1.5 diff -u -p -r1.5 security_selinux.c --- src/security_selinux.c 3 Apr 2009 10:55:51 -0000 1.5 +++ src/security_selinux.c 3 Apr 2009 12:14:54 -0000 @@ -162,11 +162,12 @@ SELinuxGenSecurityLabel(virConnectPtr co char *scontext = NULL; int c1 = 0; int c2 = 0; - if ( ( vm->def->seclabel.label ) || - ( vm->def->seclabel.model ) || - ( vm->def->seclabel.imagelabel )) { - virSecurityReportError(conn, VIR_ERR_ERROR, - "%s", _("security labellin already defined for VM")); + + if (vm->def->seclabel.label || + vm->def->seclabel.model || + vm->def->seclabel.imagelabel) { + virSecurityReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("security label already defined for VM")); return rc; } @@ -197,7 +198,7 @@ SELinuxGenSecurityLabel(virConnectPtr co goto err; } vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME); - if (! vm->def->seclabel.model) { + if (!vm->def->seclabel.model) { virReportOOMError(conn); goto err; } -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list