mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 19:32:19 +00:00
qemuDomainAttachDeviceMknod: Deal with symlinks
Similarly to one of the previous commits, we need to deal properly with symlinks in hotplug case too. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
4ac847f93b
commit
3f5fcacf89
@ -7635,6 +7635,7 @@ struct qemuDomainAttachDeviceMknodData {
|
|||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
virDomainDeviceDefPtr devDef;
|
virDomainDeviceDefPtr devDef;
|
||||||
const char *file;
|
const char *file;
|
||||||
|
const char *target;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
void *acl;
|
void *acl;
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
@ -7650,6 +7651,7 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
|
|||||||
struct qemuDomainAttachDeviceMknodData *data = opaque;
|
struct qemuDomainAttachDeviceMknodData *data = opaque;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
bool delDevice = false;
|
bool delDevice = false;
|
||||||
|
bool isLink = S_ISLNK(data->sb.st_mode);
|
||||||
|
|
||||||
virSecurityManagerPostFork(data->driver->securityManager);
|
virSecurityManagerPostFork(data->driver->securityManager);
|
||||||
|
|
||||||
@ -7659,24 +7661,47 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_DEBUG("Creating dev %s (%d,%d)",
|
if (isLink) {
|
||||||
data->file, major(data->sb.st_rdev), minor(data->sb.st_rdev));
|
VIR_DEBUG("Creating symlink %s -> %s", data->file, data->target);
|
||||||
if (mknod(data->file, data->sb.st_mode, data->sb.st_rdev) < 0) {
|
if (symlink(data->target, data->file) < 0) {
|
||||||
/* Because we are not removing devices on hotunplug, or
|
if (errno != EEXIST) {
|
||||||
* we might be creating part of backing chain that
|
virReportSystemError(errno,
|
||||||
* already exist due to a different disk plugged to
|
_("Unable to create symlink %s"),
|
||||||
* domain, accept EEXIST. */
|
data->target);
|
||||||
if (errno != EEXIST) {
|
goto cleanup;
|
||||||
virReportSystemError(errno,
|
}
|
||||||
_("Unable to create device %s"),
|
} else {
|
||||||
data->file);
|
delDevice = true;
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
delDevice = true;
|
VIR_DEBUG("Creating dev %s (%d,%d)",
|
||||||
|
data->file, major(data->sb.st_rdev), minor(data->sb.st_rdev));
|
||||||
|
if (mknod(data->file, data->sb.st_mode, data->sb.st_rdev) < 0) {
|
||||||
|
/* Because we are not removing devices on hotunplug, or
|
||||||
|
* we might be creating part of backing chain that
|
||||||
|
* already exist due to a different disk plugged to
|
||||||
|
* domain, accept EEXIST. */
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Unable to create device %s"),
|
||||||
|
data->file);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delDevice = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virFileSetACLs(data->file, data->acl) < 0 &&
|
if (lchown(data->file, data->sb.st_uid, data->sb.st_gid) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Failed to chown device %s"),
|
||||||
|
data->file);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Symlinks don't have ACLs. */
|
||||||
|
if (!isLink &&
|
||||||
|
virFileSetACLs(data->file, data->acl) < 0 &&
|
||||||
errno != ENOTSUP) {
|
errno != ENOTSUP) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
_("Unable to set ACLs on %s"), data->file);
|
_("Unable to set ACLs on %s"), data->file);
|
||||||
@ -7684,7 +7709,8 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
if (setfilecon_raw(data->file, (VIR_SELINUX_CTX_CONST char *) data->tcon) < 0) {
|
if (data->tcon &&
|
||||||
|
lsetfilecon_raw(data->file, (VIR_SELINUX_CTX_CONST char *) data->tcon) < 0) {
|
||||||
VIR_WARNINGS_NO_WLOGICALOP_EQUAL_EXPR
|
VIR_WARNINGS_NO_WLOGICALOP_EQUAL_EXPR
|
||||||
if (errno != EOPNOTSUPP && errno != ENOTSUP) {
|
if (errno != EOPNOTSUPP && errno != ENOTSUP) {
|
||||||
VIR_WARNINGS_RESET
|
VIR_WARNINGS_RESET
|
||||||
@ -7716,6 +7742,8 @@ qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
|
|||||||
{
|
{
|
||||||
struct qemuDomainAttachDeviceMknodData data;
|
struct qemuDomainAttachDeviceMknodData data;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
char *target = NULL;
|
||||||
|
bool isLink;
|
||||||
|
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
|
|
||||||
@ -7724,21 +7752,55 @@ qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
|
|||||||
data.devDef = devDef;
|
data.devDef = devDef;
|
||||||
data.file = file;
|
data.file = file;
|
||||||
|
|
||||||
if (stat(file, &data.sb) < 0) {
|
if (lstat(file, &data.sb) < 0) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
_("Unable to access %s"), file);
|
_("Unable to access %s"), file);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virFileGetACLs(file, &data.acl) < 0 &&
|
isLink = S_ISLNK(data.sb.st_mode);
|
||||||
|
|
||||||
|
if (isLink) {
|
||||||
|
if (virFileReadLink(file, &target) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("unable to resolve symlink %s"),
|
||||||
|
file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_RELATIVE_FILE_NAME(target)) {
|
||||||
|
char *c = NULL, *tmp = NULL, *fileTmp = NULL;
|
||||||
|
|
||||||
|
if (VIR_STRDUP(fileTmp, file) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if ((c = strrchr(fileTmp, '/')))
|
||||||
|
*(c + 1) = '\0';
|
||||||
|
|
||||||
|
if (virAsprintf(&tmp, "%s%s", fileTmp, target) < 0) {
|
||||||
|
VIR_FREE(fileTmp);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
VIR_FREE(fileTmp);
|
||||||
|
VIR_FREE(target);
|
||||||
|
target = tmp;
|
||||||
|
tmp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Symlinks don't have ACLs. */
|
||||||
|
if (!isLink &&
|
||||||
|
virFileGetACLs(file, &data.acl) < 0 &&
|
||||||
errno != ENOTSUP) {
|
errno != ENOTSUP) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
_("Unable to get ACLs on %s"), file);
|
_("Unable to get ACLs on %s"), file);
|
||||||
return ret;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_SELINUX
|
#ifdef WITH_SELINUX
|
||||||
if (getfilecon_raw(file, &data.tcon) < 0 &&
|
if (lgetfilecon_raw(file, &data.tcon) < 0 &&
|
||||||
(errno != ENOTSUP && errno != ENODATA)) {
|
(errno != ENOTSUP && errno != ENODATA)) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
_("Unable to get SELinux label from %s"), file);
|
_("Unable to get SELinux label from %s"), file);
|
||||||
@ -7746,17 +7808,22 @@ qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (virSecurityManagerPreFork(driver->securityManager) < 0)
|
if (STRPREFIX(file, DEVPREFIX)) {
|
||||||
goto cleanup;
|
if (virSecurityManagerPreFork(driver->securityManager) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (virProcessRunInMountNamespace(vm->pid,
|
if (virProcessRunInMountNamespace(vm->pid,
|
||||||
qemuDomainAttachDeviceMknodHelper,
|
qemuDomainAttachDeviceMknodHelper,
|
||||||
&data) < 0) {
|
&data) < 0) {
|
||||||
|
virSecurityManagerPostFork(driver->securityManager);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
virSecurityManagerPostFork(driver->securityManager);
|
virSecurityManagerPostFork(driver->securityManager);
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virSecurityManagerPostFork(driver->securityManager);
|
if (isLink &&
|
||||||
|
qemuDomainAttachDeviceMknod(driver, vm, devDef, target) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -7764,6 +7831,7 @@ qemuDomainAttachDeviceMknod(virQEMUDriverPtr driver,
|
|||||||
freecon(data.tcon);
|
freecon(data.tcon);
|
||||||
#endif
|
#endif
|
||||||
virFileFreeACLs(&data.acl);
|
virFileFreeACLs(&data.acl);
|
||||||
|
VIR_FREE(target);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user