static int qemuDomainManagedSaveLoad(virDomainObjPtr vm,
void *opaque);
+static int qemuOpenFile(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *path, int oflags,
+ bool *needUnlink, bool *bypassSecurityDriver);
+
+static int qemuOpenFileAs(uid_t fallback_uid, gid_t fallback_gid,
+ bool dynamicOwnership,
+ const char *path, int oflags,
+ bool *needUnlink, bool *bypassSecurityDriver);
+
virQEMUDriverPtr qemu_driver = NULL;
}
/* Internal function to properly create or open existing files, with
- * ownership affected by qemu driver setup. */
+ * ownership affected by qemu driver setup and domain DAC label. */
static int
-qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
+qemuOpenFile(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *path, int oflags,
bool *needUnlink, bool *bypassSecurityDriver)
+{
+ int ret = -1;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ uid_t user = cfg->user;
+ gid_t group = cfg->group;
+ bool dynamicOwnership = cfg->dynamicOwnership;
+ virSecurityLabelDefPtr seclabel;
+
+ virObjectUnref(cfg);
+
+ /* TODO: Take imagelabel into account? */
+ if (vm &&
+ (seclabel = virDomainDefGetSecurityLabelDef(vm->def, "dac")) != NULL &&
+ (virParseOwnershipIds(seclabel->label, &user, &group) < 0))
+ goto cleanup;
+
+ ret = qemuOpenFileAs(user, group, dynamicOwnership,
+ path, oflags, needUnlink, bypassSecurityDriver);
+
+ cleanup:
+ return ret;
+}
+
+static int
+qemuOpenFileAs(uid_t fallback_uid, gid_t fallback_gid,
+ bool dynamicOwnership,
+ const char *path, int oflags,
+ bool *needUnlink, bool *bypassSecurityDriver)
{
struct stat sb;
bool is_reg = true;
int path_shared = virStorageFileIsSharedFS(path);
uid_t uid = getuid();
gid_t gid = getgid();
- virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
/* path might be a pre-existing block dev, in which case
* we need to skip the create step, and also avoid unlink
/* Don't force chown on network-shared FS
* as it is likely to fail. */
- if (path_shared <= 0 || cfg->dynamicOwnership)
+ if (path_shared <= 0 || dynamicOwnership)
vfoflags |= VIR_FILE_OPEN_FORCE_OWNER;
if (stat(path, &sb) == 0) {
/* If the path is regular file which exists
* already and dynamic_ownership is off, we don't
* want to change it's ownership, just open it as-is */
- if (is_reg && !cfg->dynamicOwnership) {
+ if (is_reg && !dynamicOwnership) {
uid = sb.st_uid;
gid = sb.st_gid;
}
/* If we failed as root, and the error was permission-denied
(EACCES or EPERM), assume it's on a network-connected share
where root access is restricted (eg, root-squashed NFS). If the
- qemu user (cfg->user) is non-root, just set a flag to
+ qemu user is non-root, just set a flag to
bypass security driver shenanigans, and retry the operation
after doing setuid to qemu user */
- if ((fd != -EACCES && fd != -EPERM) || cfg->user == getuid())
+ if ((fd != -EACCES && fd != -EPERM) || fallback_uid == getuid())
goto error;
/* On Linux we can also verify the FS-type of the directory. */
goto error;
}
- /* Retry creating the file as cfg->user */
+ /* Retry creating the file as qemu user */
if ((fd = virFileOpenAs(path, oflags,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
- cfg->user, cfg->group,
+ fallback_uid, fallback_gid,
vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
virReportSystemError(-fd, oflags & O_CREAT
? _("Error from child process creating '%s'")
*needUnlink = need_unlink;
if (bypassSecurityDriver)
*bypassSecurityDriver = bypass_security;
- virObjectUnref(cfg);
return fd;
error:
goto cleanup;
}
}
- fd = qemuOpenFile(driver, path, O_WRONLY | O_TRUNC | O_CREAT | directFlag,
+ fd = qemuOpenFile(driver, vm, path,
+ O_WRONLY | O_TRUNC | O_CREAT | directFlag,
&needUnlink, &bypassSecurityDriver);
if (fd < 0)
goto cleanup;
if (virFileWrapperFdClose(wrapperFd) < 0)
goto cleanup;
- if ((fd = qemuOpenFile(driver, path, O_WRONLY, NULL, NULL)) < 0)
+ if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0)
goto cleanup;
memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
/* Core dumps usually imply last-ditch analysis efforts are
* desired, so we intentionally do not unlink even if a file was
* created. */
- if ((fd = qemuOpenFile(driver, path,
+ if ((fd = qemuOpenFile(driver, vm, path,
O_CREAT | O_TRUNC | O_WRONLY | directFlag,
NULL, NULL)) < 0)
goto cleanup;
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
goto error;
- if ((fd = qemuOpenFile(driver, path, oflags, NULL, NULL)) < 0)
+ if ((fd = qemuOpenFile(driver, NULL, path, oflags, NULL, NULL)) < 0)
goto error;
if (bypass_cache &&
!(*wrapperFd = virFileWrapperFdNew(&fd, path,
/* create the stub file and set selinux labels; manipulate disk in
* place, in a way that can be reverted on failure. */
if (!reuse) {
- fd = qemuOpenFile(driver, source, O_WRONLY | O_TRUNC | O_CREAT,
+ fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT,
&need_unlink, NULL);
if (fd < 0)
goto cleanup;
}
if (!(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
- int fd = qemuOpenFile(driver, dest, O_WRONLY | O_TRUNC | O_CREAT,
+ int fd = qemuOpenFile(driver, vm, dest, O_WRONLY | O_TRUNC | O_CREAT,
&need_unlink, NULL);
if (fd < 0)
goto endjob;