提交 c444af1a 编写于 作者: A Alex Williamson 提交者: Daniel P. Berrange

Pass pre-opened PCI device sysfs config file to QEMU

This allows libvirt to open the PCI device sysfs config file prior
to dropping privileges so qemu can access the full config space.
Without this, a de-privileged qemu can only access the first 64
bytes of config space.

* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Detect support
  for pci-assign.configfd option. Use this option when formatting
  PCI device string if possible
* src/qemu/qemu_driver.c: Pre-open PCI sysfs config file and pass
  to QEMU
上级 7f44743c
......@@ -1354,6 +1354,48 @@ fail:
return -1;
}
static void qemudParsePCIDeviceStrs(const char *qemu, unsigned long long *flags)
{
const char *const qemuarg[] = { qemu, "-device", "pci-assign,?", NULL };
const char *const qemuenv[] = { "LC_ALL=C", NULL };
pid_t child;
int status;
int newstderr = -1;
if (virExec(qemuarg, qemuenv, NULL,
&child, -1, NULL, &newstderr, VIR_EXEC_CLEAR_CAPS) < 0)
return;
char *pciassign = NULL;
enum { MAX_PCI_OUTPUT_SIZE = 1024*4 };
int len = virFileReadLimFD(newstderr, MAX_PCI_OUTPUT_SIZE, &pciassign);
if (len < 0) {
virReportSystemError(errno,
_("Unable to read %s pci-assign device output"),
qemu);
goto cleanup;
}
if (strstr(pciassign, "pci-assign.configfd"))
*flags |= QEMUD_CMD_FLAG_PCI_CONFIGFD;
cleanup:
VIR_FREE(pciassign);
close(newstderr);
rewait:
if (waitpid(child, &status, 0) != child) {
if (errno == EINTR)
goto rewait;
VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
WEXITSTATUS(status), (unsigned long)child);
}
if (WEXITSTATUS(status) != 0) {
VIR_WARN("Unexpected exit status '%d', qemu probably failed",
WEXITSTATUS(status));
}
}
int qemudExtractVersionInfo(const char *qemu,
unsigned int *retversion,
unsigned long long *retflags) {
......@@ -1387,6 +1429,9 @@ int qemudExtractVersionInfo(const char *qemu,
&version, &is_kvm, &kvm_version) == -1)
goto cleanup2;
if (flags & QEMUD_CMD_FLAG_DEVICE)
qemudParsePCIDeviceStrs(qemu, &flags);
if (retversion)
*retversion = version;
if (retflags)
......@@ -2896,8 +2941,33 @@ error:
}
int
qemudOpenPCIConfig(virDomainHostdevDefPtr dev)
{
char *path = NULL;
int configfd = -1;
if (virAsprintf(&path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config",
dev->source.subsys.u.pci.domain,
dev->source.subsys.u.pci.bus,
dev->source.subsys.u.pci.slot,
dev->source.subsys.u.pci.function) < 0) {
virReportOOMError();
return -1;
}
configfd = open(path, O_RDWR, 0);
if (configfd < 0)
virReportSystemError(errno, _("Failed opening %s"), path);
VIR_FREE(path);
return configfd;
}
char *
qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev)
qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev, const char *configfd)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
......@@ -2907,6 +2977,8 @@ qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev)
dev->source.subsys.u.pci.slot,
dev->source.subsys.u.pci.function);
virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
if (configfd && *configfd)
virBufferVSprintf(&buf, ",configfd=%s", configfd);
if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
goto error;
......@@ -4611,8 +4683,30 @@ int qemudBuildCommandLine(virConnectPtr conn,
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
char *configfd_name = NULL;
if (qemuCmdFlags & QEMUD_CMD_FLAG_PCI_CONFIGFD) {
int configfd = qemudOpenPCIConfig(hostdev);
if (configfd >= 0) {
if (virAsprintf(&configfd_name, "%d", configfd) < 0) {
close(configfd);
virReportOOMError();
goto no_memory;
}
if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
VIR_FREE(configfd_name);
close(configfd);
goto no_memory;
}
(*vmfds)[(*nvmfds)++] = configfd;
}
}
ADD_ARG_LIT("-device");
if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name);
VIR_FREE(configfd_name);
if (!devstr)
goto error;
ADD_ARG(devstr);
} else if (qemuCmdFlags & QEMUD_CMD_FLAG_PCIDEVICE) {
......
......@@ -89,6 +89,7 @@ enum qemud_cmd_flags {
QEMUD_CMD_FLAG_NO_HPET = (1LL << 33), /* -no-hpet flag is supported */
QEMUD_CMD_FLAG_NO_KVM_PIT = (1LL << 34), /* -no-kvm-pit-reinjection supported */
QEMUD_CMD_FLAG_TDF = (1LL << 35), /* -tdf flag (user-mode pit catchup) */
QEMUD_CMD_FLAG_PCI_CONFIGFD = (1LL << 36), /* pci-assign.configfd */
};
/* Main driver state */
......@@ -247,7 +248,10 @@ char * qemuBuildSoundDevStr(virDomainSoundDefPtr sound);
/* Legacy, pre device support */
char * qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev);
/* Current, best practice */
char * qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev);
char * qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev,
const char *configfd);
int qemudOpenPCIConfig(virDomainHostdevDefPtr dev);
/* Current, best practice */
char * qemuBuildChrChardevStr(virDomainChrDefPtr dev);
......
......@@ -7658,6 +7658,8 @@ static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
pciDevice *pci;
int ret;
char *devstr = NULL;
int configfd = -1;
char *configfd_name = NULL;
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
virReportOOMError();
......@@ -7688,8 +7690,32 @@ static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
goto error;
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
goto error;
if (qemuCmdFlags & QEMUD_CMD_FLAG_PCI_CONFIGFD) {
configfd = qemudOpenPCIConfig(hostdev);
if (configfd >= 0) {
if (virAsprintf(&configfd_name, "fd-%s",
hostdev->info.alias) < 0) {
virReportOOMError();
goto error;
}
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorSendFileHandle(priv->mon, configfd_name,
configfd) < 0) {
qemuDomainObjExitMonitorWithDriver(driver, vm);
goto error;
}
qemuDomainObjExitMonitorWithDriver(driver, vm);
}
}
if (!virDomainObjIsActive(vm)) {
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("guest unexpectedly quit during hotplug"));
goto error;
}
if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name)))
goto error;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
......@@ -7713,6 +7739,9 @@ static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
VIR_FREE(devstr);
VIR_FREE(configfd_name);
if (configfd >= 0)
close(configfd);
return 0;
......@@ -7724,6 +7753,9 @@ error:
VIR_FREE(devstr);
pciDeviceListDel(driver->activePciHostdevs, pci);
VIR_FREE(configfd_name);
if (configfd >= 0)
close(configfd);
return -1;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册