1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-03-20 07:59:00 +00:00

Create storage volumes directly with desired uid/gid

In order to avoid problems trying to chown files that were created by
root on a root-squashing nfs server, fork a new process that setuid's
to the desired uid before creating the file. (It's only done this way
if the pool containing the new volume is of type 'netfs', otherwise
the old method of creating the file followed by chown() is used.)

This changes the semantics of the "create_func" slightly - previously
it was assumed that this function just created the file, then the
caller would chown it to the desired uid. Now, create_func does both
operations.

There are multiple functions that can take on the role of create_func:

createFileDir - previously called mkdir(), now calls virDirCreate().
virStorageBackendCreateRaw - previously called open(),
                             now calls virFileCreate().
virStorageBackendCreateQemuImg - use virRunWithHook() to setuid/gid.
virStorageBackendCreateQcowCreate - same.
virStorageBackendCreateBlockFrom - preserve old behavior (but attempt
                                   chown when necessary even if not root)

* src/storage/storage_backend.[ch] src/storage/storage_backend_disk.c
  src/storage/storage_backend_fs.c src/storage/storage_backend_logical.c
  src/storage/storage_driver.c: change the create_func implementations,
  also propagate the pool information to be able to detect NETFS ones.
This commit is contained in:
Laine Stump 2010-01-21 00:41:52 +01:00 committed by Daniel Veillard
parent 98f6f381c8
commit e1f2778434
6 changed files with 147 additions and 61 deletions

View File

@ -205,6 +205,7 @@ cleanup:
static int static int
virStorageBackendCreateBlockFrom(virConnectPtr conn, virStorageBackendCreateBlockFrom(virConnectPtr conn,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags ATTRIBUTE_UNUSED) unsigned int flags ATTRIBUTE_UNUSED)
@ -212,6 +213,9 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn,
int fd = -1; int fd = -1;
int ret = -1; int ret = -1;
unsigned long long remain; unsigned long long remain;
struct stat st;
gid_t gid;
uid_t uid;
if ((fd = open(vol->target.path, O_RDWR)) < 0) { if ((fd = open(vol->target.path, O_RDWR)) < 0) {
virReportSystemError(conn, errno, virReportSystemError(conn, errno,
@ -229,6 +233,28 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn,
goto cleanup; goto cleanup;
} }
if (fstat(fd, &st) == -1) {
ret = errno;
virReportSystemError(conn, errno, _("stat of '%s' failed"),
vol->target.path);
goto cleanup;
}
uid = (vol->target.perms.uid != st.st_uid) ? vol->target.perms.uid : -1;
gid = (vol->target.perms.gid != st.st_gid) ? vol->target.perms.gid : -1;
if (((uid != -1) || (gid != -1))
&& (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0)) {
virReportSystemError(conn, errno,
_("cannot chown '%s' to (%u, %u)"),
vol->target.path, vol->target.perms.uid,
vol->target.perms.gid);
goto cleanup;
}
if (fchmod(fd, vol->target.perms.mode) < 0) {
virReportSystemError(conn, errno,
_("cannot set mode of '%s' to %04o"),
vol->target.path, vol->target.perms.mode);
goto cleanup;
}
if (close(fd) < 0) { if (close(fd) < 0) {
virReportSystemError(conn, errno, virReportSystemError(conn, errno,
_("cannot close file '%s'"), _("cannot close file '%s'"),
@ -247,12 +273,14 @@ cleanup:
int int
virStorageBackendCreateRaw(virConnectPtr conn, virStorageBackendCreateRaw(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags ATTRIBUTE_UNUSED) unsigned int flags ATTRIBUTE_UNUSED)
{ {
int fd = -1; int fd = -1;
int ret = -1; int ret = -1;
int createstat;
unsigned long long remain; unsigned long long remain;
char *buf = NULL; char *buf = NULL;
@ -263,14 +291,23 @@ virStorageBackendCreateRaw(virConnectPtr conn,
return -1; return -1;
} }
if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL, if ((createstat = virFileCreate(vol->target.path, vol->target.perms.mode,
vol->target.perms.mode)) < 0) { vol->target.perms.uid, vol->target.perms.gid,
virReportSystemError(conn, errno, (pool->def->type == VIR_STORAGE_POOL_NETFS
? VIR_FILE_CREATE_AS_UID : 0))) < 0) {
virReportSystemError(conn, createstat,
_("cannot create path '%s'"), _("cannot create path '%s'"),
vol->target.path); vol->target.path);
goto cleanup; goto cleanup;
} }
if ((fd = open(vol->target.path, O_RDWR | O_EXCL)) < 0) {
virReportSystemError(conn, errno,
_("cannot open new path '%s'"),
vol->target.path);
goto cleanup;
}
/* Seek to the final size, so the capacity is available upfront /* Seek to the final size, so the capacity is available upfront
* for progress reporting */ * for progress reporting */
if (ftruncate(fd, vol->capacity) < 0) { if (ftruncate(fd, vol->capacity) < 0) {
@ -453,12 +490,87 @@ cleanup:
return ret; return ret;
} }
static int virStorageBuildSetUIDHook(void *data) {
virStorageVolDefPtr vol = data;
if ((vol->target.perms.gid != 0)
&& (setgid(vol->target.perms.gid) != 0)) {
virReportSystemError(NULL, errno,
_("Cannot set gid to %u before creating %s"),
vol->target.perms.gid, vol->target.path);
return -1;
}
if ((vol->target.perms.uid != 0)
&& (setuid(vol->target.perms.uid) != 0)) {
virReportSystemError(NULL, errno,
_("Cannot set uid to %u before creating %s"),
vol->target.perms.uid, vol->target.path);
return -1;
}
return 0;
}
static int virStorageBackendCreateExecCommand(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
const char **cmdargv) {
struct stat st;
gid_t gid;
uid_t uid;
int filecreated = 0;
if ((pool->def->type == VIR_STORAGE_POOL_NETFS)
&& (getuid() == 0)
&& ((vol->target.perms.uid != 0) || (vol->target.perms.gid != 0))) {
if (virRunWithHook(conn, cmdargv,
virStorageBuildSetUIDHook, vol, NULL) == 0) {
/* command was successfully run, check if the file was created */
if (stat(vol->target.path, &st) >=0)
filecreated = 1;
}
}
if (!filecreated) {
if (virRun(conn, cmdargv, NULL) < 0) {
virReportSystemError(conn, errno,
_("Cannot run %s to create %s"),
cmdargv[0], vol->target.path);
return -1;
}
if (stat(vol->target.path, &st) < 0) {
virReportSystemError(conn, errno,
_("%s failed to create %s"),
cmdargv[0], vol->target.path);
return -1;
}
}
uid = (vol->target.perms.uid != st.st_uid) ? vol->target.perms.uid : -1;
gid = (vol->target.perms.gid != st.st_gid) ? vol->target.perms.gid : -1;
if (((uid != -1) || (gid != -1))
&& (chown(vol->target.path, uid, gid) < 0)) {
virReportSystemError(conn, errno,
_("cannot chown %s to (%u, %u)"),
vol->target.path, vol->target.perms.uid,
vol->target.perms.gid);
return -1;
}
if (chmod(vol->target.path, vol->target.perms.mode) < 0) {
virReportSystemError(conn, errno,
_("cannot set mode of '%s' to %04o"),
vol->target.path, vol->target.perms.mode);
return -1;
}
return 0;
}
static int static int
virStorageBackendCreateQemuImg(virConnectPtr conn, virStorageBackendCreateQemuImg(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags ATTRIBUTE_UNUSED) unsigned int flags ATTRIBUTE_UNUSED)
{ {
int ret;
char size[100]; char size[100];
char *create_tool; char *create_tool;
short use_kvmimg; short use_kvmimg;
@ -616,14 +728,10 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
/* Size in KB */ /* Size in KB */
snprintf(size, sizeof(size), "%lluK", vol->capacity/1024); snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
if (virRun(conn, imgargv, NULL) < 0) { ret = virStorageBackendCreateExecCommand(conn, pool, vol, imgargv);
VIR_FREE(imgargv[0]);
return -1;
}
VIR_FREE(imgargv[0]); VIR_FREE(imgargv[0]);
return 0; return ret;
} }
/* /*
@ -632,10 +740,12 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
*/ */
static int static int
virStorageBackendCreateQcowCreate(virConnectPtr conn, virStorageBackendCreateQcowCreate(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags ATTRIBUTE_UNUSED) unsigned int flags ATTRIBUTE_UNUSED)
{ {
int ret;
char size[100]; char size[100];
const char *imgargv[4]; const char *imgargv[4];
@ -672,14 +782,10 @@ virStorageBackendCreateQcowCreate(virConnectPtr conn,
imgargv[2] = vol->target.path; imgargv[2] = vol->target.path;
imgargv[3] = NULL; imgargv[3] = NULL;
if (virRun(conn, imgargv, NULL) < 0) { ret = virStorageBackendCreateExecCommand(conn, pool, vol, imgargv);
VIR_FREE(imgargv[0]);
return -1;
}
VIR_FREE(imgargv[0]); VIR_FREE(imgargv[0]);
return 0; return ret;
} }
virStorageBackendBuildVolFrom virStorageBackendBuildVolFrom

View File

@ -35,14 +35,18 @@ typedef int (*virStorageBackendRefreshPool)(virConnectPtr conn, virStoragePoolOb
typedef int (*virStorageBackendStopPool)(virConnectPtr conn, virStoragePoolObjPtr pool); typedef int (*virStorageBackendStopPool)(virConnectPtr conn, virStoragePoolObjPtr pool);
typedef int (*virStorageBackendDeletePool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags); typedef int (*virStorageBackendDeletePool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags);
typedef int (*virStorageBackendBuildVol)(virConnectPtr conn, virStorageVolDefPtr vol); typedef int (*virStorageBackendBuildVol)(virConnectPtr conn,
virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
typedef int (*virStorageBackendCreateVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol); typedef int (*virStorageBackendCreateVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
typedef int (*virStorageBackendRefreshVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol); typedef int (*virStorageBackendRefreshVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags); typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags);
typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStorageVolDefPtr origvol, virStorageVolDefPtr newvol, unsigned int flags); typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStoragePoolObjPtr pool,
virStorageVolDefPtr origvol, virStorageVolDefPtr newvol,
unsigned int flags);
/* File creation/cloning functions used for cloning between backends */ /* File creation/cloning functions used for cloning between backends */
int virStorageBackendCreateRaw(virConnectPtr conn, int virStorageBackendCreateRaw(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags); unsigned int flags);

View File

@ -599,6 +599,7 @@ virStorageBackendDiskCreateVol(virConnectPtr conn,
static int static int
virStorageBackendDiskBuildVolFrom(virConnectPtr conn, virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags) unsigned int flags)
@ -609,7 +610,7 @@ virStorageBackendDiskBuildVolFrom(virConnectPtr conn,
if (!build_func) if (!build_func)
return -1; return -1;
return build_func(conn, vol, inputvol, flags); return build_func(conn, pool, vol, inputvol, flags);
} }
static int static int

View File

@ -737,9 +737,12 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn,
} }
static int createFileDir(virConnectPtr conn, static int createFileDir(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags ATTRIBUTE_UNUSED) { unsigned int flags ATTRIBUTE_UNUSED) {
int err;
if (inputvol) { if (inputvol) {
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
"%s", "%s",
@ -747,9 +750,11 @@ static int createFileDir(virConnectPtr conn,
return -1; return -1;
} }
if (mkdir(vol->target.path, vol->target.perms.mode) < 0) { if ((err = virDirCreate(vol->target.path, vol->target.perms.mode,
virReportSystemError(conn, errno, vol->target.perms.uid, vol->target.perms.gid,
_("cannot create path '%s'"), (pool->def->type == VIR_STORAGE_POOL_NETFS
? VIR_FILE_CREATE_AS_UID : 0))) != 0) {
virReportSystemError(conn, err, _("cannot create path '%s'"),
vol->target.path); vol->target.path);
return -1; return -1;
} }
@ -759,10 +764,10 @@ static int createFileDir(virConnectPtr conn,
static int static int
_virStorageBackendFileSystemVolBuild(virConnectPtr conn, _virStorageBackendFileSystemVolBuild(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol) virStorageVolDefPtr inputvol)
{ {
int fd;
virStorageBackendBuildVolFrom create_func; virStorageBackendBuildVolFrom create_func;
int tool_type; int tool_type;
@ -794,41 +799,8 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn,
return -1; return -1;
} }
if (create_func(conn, vol, inputvol, 0) < 0) if (create_func(conn, pool, vol, inputvol, 0) < 0)
return -1; return -1;
if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
virReportSystemError(conn, errno,
_("cannot read path '%s'"),
vol->target.path);
return -1;
}
/* We can only chown/grp if root */
if (getuid() == 0) {
if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
virReportSystemError(conn, errno,
_("cannot set file owner '%s'"),
vol->target.path);
close(fd);
return -1;
}
}
if (fchmod(fd, vol->target.perms.mode) < 0) {
virReportSystemError(conn, errno,
_("cannot set file mode '%s'"),
vol->target.path);
close(fd);
return -1;
}
if (close(fd) < 0) {
virReportSystemError(conn, errno,
_("cannot close file '%s'"),
vol->target.path);
return -1;
}
return 0; return 0;
} }
@ -839,8 +811,9 @@ _virStorageBackendFileSystemVolBuild(virConnectPtr conn,
*/ */
static int static int
virStorageBackendFileSystemVolBuild(virConnectPtr conn, virStorageBackendFileSystemVolBuild(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol) { virStorageVolDefPtr vol) {
return _virStorageBackendFileSystemVolBuild(conn, vol, NULL); return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL);
} }
/* /*
@ -848,10 +821,11 @@ virStorageBackendFileSystemVolBuild(virConnectPtr conn,
*/ */
static int static int
virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn, virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags ATTRIBUTE_UNUSED) { unsigned int flags ATTRIBUTE_UNUSED) {
return _virStorageBackendFileSystemVolBuild(conn, vol, inputvol); return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol);
} }
/** /**

View File

@ -660,6 +660,7 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
static int static int
virStorageBackendLogicalBuildVolFrom(virConnectPtr conn, virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
unsigned int flags) unsigned int flags)
@ -670,7 +671,7 @@ virStorageBackendLogicalBuildVolFrom(virConnectPtr conn,
if (!build_func) if (!build_func)
return -1; return -1;
return build_func(conn, vol, inputvol, flags); return build_func(conn, pool, vol, inputvol, flags);
} }
static int static int

View File

@ -1331,7 +1331,7 @@ storageVolumeCreateXML(virStoragePoolPtr obj,
voldef->building = 1; voldef->building = 1;
virStoragePoolObjUnlock(pool); virStoragePoolObjUnlock(pool);
buildret = backend->buildVol(obj->conn, buildvoldef); buildret = backend->buildVol(obj->conn, pool, buildvoldef);
storageDriverLock(driver); storageDriverLock(driver);
virStoragePoolObjLock(pool); virStoragePoolObjLock(pool);
@ -1484,7 +1484,7 @@ storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
virStoragePoolObjUnlock(origpool); virStoragePoolObjUnlock(origpool);
} }
buildret = backend->buildVolFrom(obj->conn, newvol, origvol, flags); buildret = backend->buildVolFrom(obj->conn, pool, newvol, origvol, flags);
storageDriverLock(driver); storageDriverLock(driver);
virStoragePoolObjLock(pool); virStoragePoolObjLock(pool);