1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-09-20 05:44:53 +03:00

Compare commits

...

10 Commits

Author SHA1 Message Date
Jiri Denemark
49fa383bb0 qemu: Let empty default VNC password work as documented
CVE-2016-5008

Setting an empty graphics password is documented as a way to disable
VNC/SPICE access, but QEMU does not always behaves like that. VNC would
happily accept the empty password. Let's enforce the behavior by setting
password expiration to "now".

https://bugzilla.redhat.com/show_bug.cgi?id=1180092

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit bb848feec0)
2016-06-30 12:51:13 +01:00
Eric Blake
08acad56ce CVE-2015-5313: storage: don't allow '/' in filesystem volume names
The libvirt file system storage driver determines what file to
act on by concatenating the pool location with the volume name.
If a user is able to pick names like "../../../etc/passwd", then
they can escape the bounds of the pool.  For that matter,
virStoragePoolListVolumes() doesn't descend into subdirectories,
so a user really shouldn't use a name with a slash.

Normally, only privileged users can coerce libvirt into creating
or opening existing files using the virStorageVol APIs; and such
users already have full privilege to create any domain XML (so it
is not an escalation of privilege).  But in the case of
fine-grained ACLs, it is feasible that a user can be granted
storage_vol:create but not domain:write, and it violates
assumptions if such a user can abuse libvirt to access files
outside of the storage pool.

Therefore, prevent all use of volume names that contain "/",
whether or not such a name is actually attempting to escape the
pool.

This changes things from:

$ virsh vol-create-as default ../../../../../../etc/haha --capacity 128
Vol ../../../../../../etc/haha created
$ rm /etc/haha

to:

$ virsh vol-create-as default ../../../../../../etc/haha --capacity 128
error: Failed to create vol ../../../../../../etc/haha
error: Requested operation is not valid: volume name '../../../../../../etc/haha' cannot contain '/'

Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 034e47c338)
2015-12-12 20:38:40 -07:00
Michal Privoznik
4268b1f102 remoteClientCloseFunc: Don't mangle connection object refcount
Well, in 8ad126e6 we tried to fix a memory corruption problem.
However, the fix was not as good as it could be. I mean, the
commit has one line more than it should. I've noticed this output
just recently:

  # ./run valgrind --leak-check=full --show-reachable=yes ./tools/virsh domblklist gentoo
  ==17019== Memcheck, a memory error detector
  ==17019== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
  ==17019== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
  ==17019== Command: /home/zippy/work/libvirt/libvirt.git/tools/.libs/virsh domblklist gentoo
  ==17019==
  Target     Source
  ------------------------------------------------
  fda        /var/lib/libvirt/images/fd.img
  vda        /var/lib/libvirt/images/gentoo.qcow2
  hdc        /home/zippy/tmp/install-amd64-minimal-20150402.iso

  ==17019== Thread 2:
  ==17019== Invalid read of size 4
  ==17019==    at 0x4EFF5B4: virObjectUnref (virobject.c:258)
  ==17019==    by 0x5038CFF: remoteClientCloseFunc (remote_driver.c:552)
  ==17019==    by 0x5069D57: virNetClientCloseLocked (virnetclient.c:685)
  ==17019==    by 0x506C848: virNetClientIncomingEvent (virnetclient.c:1852)
  ==17019==    by 0x5082136: virNetSocketEventHandle (virnetsocket.c:1913)
  ==17019==    by 0x4ECD64E: virEventPollDispatchHandles (vireventpoll.c:509)
  ==17019==    by 0x4ECDE02: virEventPollRunOnce (vireventpoll.c:658)
  ==17019==    by 0x4ECBF00: virEventRunDefaultImpl (virevent.c:308)
  ==17019==    by 0x130386: vshEventLoop (vsh.c:1864)
  ==17019==    by 0x4F1EB07: virThreadHelper (virthread.c:206)
  ==17019==    by 0xA8462D3: start_thread (in /lib64/libpthread-2.20.so)
  ==17019==    by 0xAB441FC: clone (in /lib64/libc-2.20.so)
  ==17019==  Address 0x139023f4 is 4 bytes inside a block of size 240 free'd
  ==17019==    at 0x4C2B1F0: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
  ==17019==    by 0x4EA8949: virFree (viralloc.c:582)
  ==17019==    by 0x4EFF6D0: virObjectUnref (virobject.c:273)
  ==17019==    by 0x4FE74D6: virConnectClose (libvirt.c:1390)
  ==17019==    by 0x13342A: virshDeinit (virsh.c:406)
  ==17019==    by 0x134A37: main (virsh.c:950)

The problem is, when registering remoteClientCloseFunc(), it's
conn->closeCallback which is ref'd. But in the function itself
it's conn->closeCallback->conn what is unref'd. This is causing
imbalance in reference counting. Moreover, there's no need for
the remote driver to increase/decrease conn refcount since it's
not used anywhere. It's just merely passed to client registered
callback. And for that purpose it's correctly ref'd in
virConnectRegisterCloseCallback() and then unref'd in
virConnectUnregisterCloseCallback().

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
(cherry picked from commit e689300770)
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-09-03 17:46:14 +02:00
John Ferlan
d055989083 storage: Correct the 'mode' check
Commit id '7c2d65dde2' changed the default value of mode to be -1 if not
supplied in the XML, which should cause creation of the volume using the
default mode of VIR_STORAGE_DEFAULT_VOL_PERM_MODE; however, the check
made was whether mode was '0' or not to use default or provided value.

This patch fixes the issue to check if the 'mode' was provided in the XML
and use that value.

(cherry picked from commit 691dd388ae)
2015-09-02 18:47:13 -04:00
John Ferlan
98242f94cd storage: Handle failure from refreshVol
Commit id '155ca616' added the 'refreshVol' API. In an NFS root-squash
environment it was possible that if the just created volume from XML wasn't
properly created with the right uid/gid and/or mode, then the followup
refreshVol will fail to open the volume in order to get the allocation/
capacity values. This would leave the volume still on the server and
cause a libvirtd crash because 'voldef' would be in the pool list, but
the cleanup code would free it.

(cherry picked from commit db9277a39b)
2015-09-02 18:47:06 -04:00
John Ferlan
a3ee6885d9 virfile: Introduce virFileUnlink
In an NFS root-squashed environment the 'vol-delete' command will fail to
'unlink' the target volume since it was created under a different uid:gid.

This code continues the concepts introduced in virFileOpenForked and
virDirCreate[NoFork] with respect to running the unlink command under
the uid/gid of the child. Unlike the other two, don't retry on EACCES
(that's why we're here doing this now).

(cherry picked from commit 35847860f6)
2015-09-02 18:46:56 -04:00
Jim Fehlig
a0080cbc17 Revert "LXC: show used memory as 0 when domain is not active"
This reverts commit 1ce7c1d20c,
which introduced a significant semantic change to the
virDomainGetInfo() API. Additionally, the change was only
made to 2 of the 15 virt drivers.

Conflicts:
	src/qemu/qemu_driver.c

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
(cherry picked from commit 60acb38abb)
2015-08-28 10:44:07 -06:00
Christophe Fergeau
45e32f2ea5 storage: fs: Fix pool building when directory already exists
Currently, when trying to virsh pool-define/virsh pool-build a new
'dir' pool, if the target directory already exists, virsh
pool-build/virStoragePoolBuild will error out. This is a change of
behaviour compared to eg libvirt 1.2.13

This is caused by the wrong type being used for the dir_create_flags
variable in virStorageBackendFileSystemBuild , it's defined as a bool
but is used as a flag bit field so should be unsigned int (this matches
the type virDirCreate expects for this variable).

This should fix https://bugzilla.gnome.org/show_bug.cgi?id=752417 (GNOME
Boxes) and https://bugzilla.redhat.com/show_bug.cgi?id=1244080
(downstream virt-manager).
2015-07-17 15:35:41 +02:00
Martin Kletzander
02b9226ee3 rpc: Rework timerActive logic in daemon
Daemon used false logic for determining whether there were any clients.
When the timer was inactive, it was activated if at least one of the
servers did not have clients.  So the bool was being flipped there and
back all the time in case there was one client, for example.

Initially introduced by fa14207368.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1240283

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
(cherry picked from commit b7ea58c262)
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-07-10 15:08:51 +02:00
Martin Kletzander
ea16e3ef07 rpc: Add virNetDaemonHasClients
So callers don't have to iterate over each server.

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
(cherry picked from commit 699faeacb1)
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2015-07-10 15:08:43 +02:00
13 changed files with 170 additions and 40 deletions

View File

@@ -1447,6 +1447,7 @@ virFileSanitizePath;
virFileSkipRoot;
virFileStripSuffix;
virFileTouch;
virFileUnlink;
virFileUnlock;
virFileUpdatePerm;
virFileWaitForDevices;

View File

@@ -65,6 +65,7 @@ virNetDaemonAddSignalHandler;
virNetDaemonAutoShutdown;
virNetDaemonClose;
virNetDaemonGetServer;
virNetDaemonHasClients;
virNetDaemonIsPrivileged;
virNetDaemonNew;
virNetDaemonNewPostExecRestart;

View File

@@ -597,7 +597,7 @@ static int lxcDomainGetInfo(virDomainPtr dom,
if (!virDomainObjIsActive(vm)) {
info->cpuTime = 0;
info->memory = 0;
info->memory = vm->def->mem.cur_balloon;
} else {
if (virCgroupGetCpuacctUsage(priv->cgroup, &(info->cpuTime)) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,

View File

@@ -2641,13 +2641,13 @@ qemuDomainGetInfo(virDomainPtr dom,
goto cleanup;
}
if (virDomainObjIsActive(vm)) {
if (VIR_ASSIGN_IS_OVERFLOW(info->memory, vm->def->mem.cur_balloon)) {
virReportError(VIR_ERR_OVERFLOW, "%s",
_("Current memory size too large"));
goto cleanup;
}
if (VIR_ASSIGN_IS_OVERFLOW(info->memory, vm->def->mem.cur_balloon)) {
virReportError(VIR_ERR_OVERFLOW, "%s",
_("Current memory size too large"));
goto cleanup;
}
if (virDomainObjIsActive(vm)) {
if (qemuGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("cannot read cputime for domain"));

View File

@@ -4026,6 +4026,7 @@ qemuDomainChangeGraphicsPasswords(virQEMUDriverPtr driver,
time_t now = time(NULL);
char expire_time [64];
const char *connected = NULL;
const char *password;
int ret = -1;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
@@ -4033,16 +4034,14 @@ qemuDomainChangeGraphicsPasswords(virQEMUDriverPtr driver,
ret = 0;
goto cleanup;
}
password = auth->passwd ? auth->passwd : defaultPasswd;
if (auth->connected)
connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected);
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
goto cleanup;
ret = qemuMonitorSetPassword(priv->mon,
type,
auth->passwd ? auth->passwd : defaultPasswd,
connected);
ret = qemuMonitorSetPassword(priv->mon, type, password, connected);
if (ret == -2) {
if (type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
@@ -4050,14 +4049,15 @@ qemuDomainChangeGraphicsPasswords(virQEMUDriverPtr driver,
_("Graphics password only supported for VNC"));
ret = -1;
} else {
ret = qemuMonitorSetVNCPassword(priv->mon,
auth->passwd ? auth->passwd : defaultPasswd);
ret = qemuMonitorSetVNCPassword(priv->mon, password);
}
}
if (ret != 0)
goto end_job;
if (auth->expires) {
if (password[0] == '\0') {
snprintf(expire_time, sizeof(expire_time), "now");
} else if (auth->expires) {
time_t lifetime = auth->validTo - now;
if (lifetime <= 0)
snprintf(expire_time, sizeof(expire_time), "now");

View File

@@ -546,10 +546,6 @@ remoteClientCloseFunc(virNetClientPtr client ATTRIBUTE_UNUSED,
cbdata->freeCallback = NULL;
}
virObjectUnlock(cbdata);
/* free the connection reference that comes along with the callback
* registration */
virObjectUnref(cbdata->conn);
}
/* helper macro to ease extraction of arguments from the URI */

View File

@@ -682,23 +682,17 @@ virNetDaemonRun(virNetDaemonPtr dmn)
*/
if (dmn->autoShutdownTimeout) {
if (timerActive) {
for (i = 0; i < dmn->nservers; i++) {
if (virNetServerHasClients(dmn->servers[i])) {
VIR_DEBUG("Deactivating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid, -1);
timerActive = false;
break;
}
if (virNetDaemonHasClients(dmn)) {
VIR_DEBUG("Deactivating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid, -1);
timerActive = false;
}
} else {
for (i = 0; i < dmn->nservers; i++) {
if (!virNetServerHasClients(dmn->servers[i])) {
VIR_DEBUG("Activating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid,
dmn->autoShutdownTimeout * 1000);
timerActive = true;
break;
}
if (!virNetDaemonHasClients(dmn)) {
VIR_DEBUG("Activating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid,
dmn->autoShutdownTimeout * 1000);
timerActive = true;
}
}
}
@@ -747,3 +741,16 @@ virNetDaemonClose(virNetDaemonPtr dmn)
virObjectUnlock(dmn);
}
bool
virNetDaemonHasClients(virNetDaemonPtr dmn)
{
size_t i = 0;
for (i = 0; i < dmn->nservers; i++) {
if (virNetServerHasClients(dmn->servers[i]))
return true;
}
return false;
}

View File

@@ -76,6 +76,8 @@ void virNetDaemonQuit(virNetDaemonPtr dmn);
void virNetDaemonClose(virNetDaemonPtr dmn);
bool virNetDaemonHasClients(virNetDaemonPtr dmn);
virNetServerPtr virNetDaemonGetServer(virNetDaemonPtr dmn,
int subServerID);

View File

@@ -479,6 +479,7 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
int fd = -1;
int operation_flags;
bool reflink_copy = false;
mode_t open_mode = VIR_STORAGE_DEFAULT_VOL_PERM_MODE;
virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
VIR_STORAGE_VOL_CREATE_REFLINK,
@@ -511,11 +512,12 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
if (pool->def->type == VIR_STORAGE_POOL_NETFS)
operation_flags |= VIR_FILE_OPEN_FORK;
if (vol->target.perms->mode != (mode_t) -1)
open_mode = vol->target.perms->mode;
if ((fd = virFileOpenAs(vol->target.path,
O_RDWR | O_CREAT | O_EXCL,
(vol->target.perms->mode ?
VIR_STORAGE_DEFAULT_VOL_PERM_MODE :
vol->target.perms->mode),
open_mode,
vol->target.perms->uid,
vol->target.perms->gid,
operation_flags)) < 0) {

View File

@@ -1,7 +1,7 @@
/*
* storage_backend_fs.c: storage backend for FS and directory handling
*
* Copyright (C) 2007-2014 Red Hat, Inc.
* Copyright (C) 2007-2015 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
@@ -784,7 +784,8 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
char *parent = NULL;
char *p = NULL;
mode_t mode;
bool needs_create_as_uid, dir_create_flags;
bool needs_create_as_uid;
unsigned int dir_create_flags;
virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
@@ -1056,6 +1057,14 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
else
vol->type = VIR_STORAGE_VOL_FILE;
/* Volumes within a directory pools are not recursive; do not
* allow escape to ../ or a subdir */
if (strchr(vol->name, '/')) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("volume name '%s' cannot contain '/'"), vol->name);
return -1;
}
VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
pool->def->target.path,
@@ -1202,7 +1211,8 @@ virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
switch ((virStorageVolType) vol->type) {
case VIR_STORAGE_VOL_FILE:
if (unlink(vol->target.path) < 0) {
if (virFileUnlink(vol->target.path, vol->target.perms->uid,
vol->target.perms->gid) < 0) {
/* Silently ignore failures where the vol has already gone away */
if (errno != ENOENT) {
virReportSystemError(errno,

View File

@@ -1864,8 +1864,12 @@ storageVolCreateXML(virStoragePoolPtr obj,
goto cleanup;
if (backend->refreshVol &&
backend->refreshVol(obj->conn, pool, voldef) < 0)
backend->refreshVol(obj->conn, pool, voldef) < 0) {
storageVolDeleteInternal(volobj, backend, pool, voldef,
0, false);
voldef = NULL;
goto cleanup;
}
/* Update pool metadata ignoring the disk backend since
* it updates the pool values.

View File

@@ -2280,6 +2280,112 @@ virFileOpenAs(const char *path, int openflags, mode_t mode,
return ret;
}
/* virFileUnlink:
* @path: file to unlink
* @uid: uid that was used to create the file (not required)
* @gid: gid that was used to create the file (not required)
*
* If a file/volume was created in an NFS root-squash environment,
* then we must 'unlink' the file in the same environment. Unlike
* the virFileOpenAs[Forked] and virDirCreate[NoFork], this code
* takes no extra flags and does not bother with EACCES failures
* from the child.
*/
int
virFileUnlink(const char *path,
uid_t uid,
gid_t gid)
{
pid_t pid;
int waitret;
int status, ret = 0;
gid_t *groups;
int ngroups;
/* If not running as root or if a non explicit uid/gid was being used for
* the file/volume, then use unlink directly
*/
if ((geteuid() != 0) ||
((uid == (uid_t) -1) && (gid == (gid_t) -1)))
return unlink(path);
/* Otherwise, we have to deal with the NFS root-squash craziness
* to run under the uid/gid that created the volume in order to
* perform the unlink of the volume.
*/
if (uid == (uid_t) -1)
uid = geteuid();
if (gid == (gid_t) -1)
gid = getegid();
ngroups = virGetGroupList(uid, gid, &groups);
if (ngroups < 0)
return -errno;
pid = virFork();
if (pid < 0) {
ret = -errno;
VIR_FREE(groups);
return ret;
}
if (pid) { /* parent */
/* wait for child to complete, and retrieve its exit code */
VIR_FREE(groups);
while ((waitret = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
if (waitret == -1) {
ret = -errno;
virReportSystemError(errno,
_("failed to wait for child unlinking '%s'"),
path);
goto parenterror;
}
/*
* If waitpid succeeded, but if the child exited abnormally or
* reported non-zero status, report failure
*/
if (!WIFEXITED(status) || (WEXITSTATUS(status)) != 0) {
char *msg = virProcessTranslateStatus(status);
virReportError(VIR_ERR_INTERNAL_ERROR,
_("child failed to unlink '%s': %s"),
path, msg);
VIR_FREE(msg);
if (WIFEXITED(status))
ret = -WEXITSTATUS(status);
else
ret = -EACCES;
}
parenterror:
return ret;
}
/* child */
/* set desired uid/gid, then attempt to unlink the file */
if (virSetUIDGID(uid, gid, groups, ngroups) < 0) {
ret = errno;
goto childerror;
}
if (unlink(path) < 0) {
ret = errno;
goto childerror;
}
childerror:
if ((ret & 0xff) != ret) {
VIR_WARN("unable to pass desired return value %d", ret);
ret = 0xff;
}
_exit(ret);
}
/* return -errno on failure, or 0 on success */
static int
virDirCreateNoFork(const char *path,

View File

@@ -219,6 +219,7 @@ int virFileOpenAs(const char *path, int openflags, mode_t mode,
uid_t uid, gid_t gid,
unsigned int flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
int virFileUnlink(const char *path, uid_t uid, gid_t gid);
enum {
VIR_DIR_CREATE_NONE = 0,