c401cc
From c6d47123ce2de0ae10ce95b717463a7490b0f9e7 Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <c6d47123ce2de0ae10ce95b717463a7490b0f9e7.1390394206.git.jdenemar@redhat.com>
c401cc
From: Martin Kletzander <mkletzan@redhat.com>
c401cc
Date: Mon, 13 Jan 2014 12:09:21 +0100
c401cc
Subject: [PATCH] CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=1049137
c401cc
c401cc
The function doesn't check whether the request is made for active or
c401cc
inactive domain.  Thus when the domain is not running it still tries
c401cc
accessing non-existing cgroups (priv->cgroup, which is NULL).
c401cc
c401cc
I re-made the function in order for it to work the same way it's qemu
c401cc
counterpart does.
c401cc
c401cc
Reproducer:
c401cc
 1) Define an LXC domain
c401cc
 2) Do 'virsh memtune <domain>'
c401cc
c401cc
Backtrace:
c401cc
 Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
c401cc
 #0  0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
c401cc
     key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
c401cc
 #1  0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
c401cc
     key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
c401cc
 #2  0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
c401cc
     key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
c401cc
 #3  0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
c401cc
     at util/vircgroup.c:1962
c401cc
 #4  0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
c401cc
     params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
c401cc
 #5  0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
c401cc
     params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
c401cc
 #6  0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
c401cc
     client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
c401cc
     ret=0x7fffd4002420) at remote.c:1895
c401cc
 #7  0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
c401cc
     client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
c401cc
     ret=0x7fffd4002420) at remote_dispatch.h:4050
c401cc
 #8  0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
c401cc
     server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
c401cc
     at rpc/virnetserverprogram.c:435
c401cc
 #9  0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
c401cc
     server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
c401cc
     at rpc/virnetserverprogram.c:305
c401cc
 #10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
c401cc
     prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
c401cc
 #11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
c401cc
     at rpc/virnetserver.c:186
c401cc
 #12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
c401cc
 #13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
c401cc
 #14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
c401cc
 #15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
c401cc
c401cc
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
c401cc
(cherry picked from commit f8c1cb90213508c4f32549023b0572ed774e48aa)
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 src/lxc/lxc_driver.c | 41 ++++++++++++++++++++++++++++++++++-------
c401cc
 1 file changed, 34 insertions(+), 7 deletions(-)
c401cc
c401cc
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
c401cc
index b746ffd..90d4878 100644
c401cc
--- a/src/lxc/lxc_driver.c
c401cc
+++ b/src/lxc/lxc_driver.c
c401cc
@@ -794,22 +794,36 @@ lxcDomainGetMemoryParameters(virDomainPtr dom,
c401cc
                              int *nparams,
c401cc
                              unsigned int flags)
c401cc
 {
c401cc
-    size_t i;
c401cc
+    virCapsPtr caps = NULL;
c401cc
+    virDomainDefPtr vmdef = NULL;
c401cc
     virDomainObjPtr vm = NULL;
c401cc
+    virLXCDomainObjPrivatePtr priv = NULL;
c401cc
+    virLXCDriverPtr driver = dom->conn->privateData;
c401cc
     unsigned long long val;
c401cc
     int ret = -1;
c401cc
-    virLXCDomainObjPrivatePtr priv;
c401cc
+    size_t i;
c401cc
 
c401cc
-    virCheckFlags(0, -1);
c401cc
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
c401cc
+                  VIR_DOMAIN_AFFECT_CONFIG, -1);
c401cc
 
c401cc
     if (!(vm = lxcDomObjFromDomain(dom)))
c401cc
         goto cleanup;
c401cc
 
c401cc
     priv = vm->privateData;
c401cc
 
c401cc
-    if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0)
c401cc
+    if (virDomainGetMemoryParametersEnsureACL(dom->conn, vm->def) < 0 ||
c401cc
+        !(caps = virLXCDriverGetCapabilities(driver, false)) ||
c401cc
+        virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
c401cc
+                                        vm, &flags, &vmdef) < 0)
c401cc
         goto cleanup;
c401cc
 
c401cc
+    if (flags & VIR_DOMAIN_AFFECT_LIVE &&
c401cc
+        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
c401cc
+        virReportError(VIR_ERR_OPERATION_INVALID,
c401cc
+                       "%s", _("cgroup memory controller is not mounted"));
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
     if ((*nparams) == 0) {
c401cc
         /* Current number of memory parameters supported by cgroups */
c401cc
         *nparams = LXC_NB_MEM_PARAM;
c401cc
@@ -823,22 +837,34 @@ lxcDomainGetMemoryParameters(virDomainPtr dom,
c401cc
 
c401cc
         switch (i) {
c401cc
         case 0: /* fill memory hard limit here */
c401cc
-            if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0)
c401cc
+            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
c401cc
+                val = vmdef->mem.hard_limit;
c401cc
+                val = val ? val : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
c401cc
+            } else if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0) {
c401cc
                 goto cleanup;
c401cc
+            }
c401cc
             if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
c401cc
                                         VIR_TYPED_PARAM_ULLONG, val) < 0)
c401cc
                 goto cleanup;
c401cc
             break;
c401cc
         case 1: /* fill memory soft limit here */
c401cc
-            if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0)
c401cc
+            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
c401cc
+                val = vmdef->mem.soft_limit;
c401cc
+                val = val ? val : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
c401cc
+            } else if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0) {
c401cc
                 goto cleanup;
c401cc
+            }
c401cc
             if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
c401cc
                                         VIR_TYPED_PARAM_ULLONG, val) < 0)
c401cc
                 goto cleanup;
c401cc
             break;
c401cc
         case 2: /* fill swap hard limit here */
c401cc
-            if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0)
c401cc
+            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
c401cc
+                val = vmdef->mem.swap_hard_limit;
c401cc
+                val = val ? val : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
c401cc
+            } else if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
c401cc
                 goto cleanup;
c401cc
+            }
c401cc
             if (virTypedParameterAssign(param,
c401cc
                                         VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
c401cc
                                         VIR_TYPED_PARAM_ULLONG, val) < 0)
c401cc
@@ -859,6 +885,7 @@ lxcDomainGetMemoryParameters(virDomainPtr dom,
c401cc
 cleanup:
c401cc
     if (vm)
c401cc
         virObjectUnlock(vm);
c401cc
+    virObjectUnref(caps);
c401cc
     return ret;
c401cc
 }
c401cc
 
c401cc
-- 
c401cc
1.8.5.3
c401cc