commit 6b36b1426d3262aaf9756b92d6e65b5c5cb1a523
Author: Martin Kletzander <mkletzan@redhat.com>
Date:   Mon Dec 9 11:15:11 2013 +0100

    security: fix crash in lxcDomainGetMemoryParameters
    
    The function doesn't check whether the request is made for active or
    inactive domain.  Thus when the domain is not running it still tries
    accessing non-existing cgroups (priv->cgroup, which is NULL).
    
    I re-made the function in order for it to work the same way it's qemu
    counterpart does.
    
    Reproducer:
     1) Define an LXC domain
     2) Do 'virsh memtune <domain>'
    
    Backtrace:
     Thread 6 (Thread 0x7fffec8c0700 (LWP 13387)):
     #0  0x00007ffff70edcc4 in virCgroupPathOfController (group=0x0, controller=3,
         key=0x7ffff75734bd "memory.limit_in_bytes", path=0x7fffec8bf750) at util/vircgroup.c:1764
     #1  0x00007ffff70e958c in virCgroupGetValueStr (group=0x0, controller=3,
         key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf7c0) at util/vircgroup.c:705
     #2  0x00007ffff70e9d29 in virCgroupGetValueU64 (group=0x0, controller=3,
         key=0x7ffff75734bd "memory.limit_in_bytes", value=0x7fffec8bf810) at util/vircgroup.c:804
     #3  0x00007ffff70ee706 in virCgroupGetMemoryHardLimit (group=0x0, kb=0x7fffec8bf8a8)
         at util/vircgroup.c:1962
     #4  0x00005555557d590f in lxcDomainGetMemoryParameters (dom=0x7fffd40024a0,
         params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at lxc/lxc_driver.c:826
     #5  0x00007ffff72c28d3 in virDomainGetMemoryParameters (domain=0x7fffd40024a0,
         params=0x7fffd40027a0, nparams=0x7fffec8bfa24, flags=0) at libvirt.c:4137
     #6  0x000055555563714d in remoteDispatchDomainGetMemoryParameters (server=0x555555eb7e00,
         client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
         ret=0x7fffd4002420) at remote.c:1895
     #7  0x00005555556052c4 in remoteDispatchDomainGetMemoryParametersHelper (server=0x555555eb7e00,
         client=0x555555ebaef0, msg=0x555555ebb3e0, rerr=0x7fffec8bfb70, args=0x7fffd40024e0,
         ret=0x7fffd4002420) at remote_dispatch.h:4050
     #8  0x00007ffff73b293f in virNetServerProgramDispatchCall (prog=0x555555ec3ae0,
         server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
         at rpc/virnetserverprogram.c:435
     #9  0x00007ffff73b207f in virNetServerProgramDispatch (prog=0x555555ec3ae0,
         server=0x555555eb7e00, client=0x555555ebaef0, msg=0x555555ebb3e0)
         at rpc/virnetserverprogram.c:305
     #10 0x00007ffff73a4d2c in virNetServerProcessMsg (srv=0x555555eb7e00, client=0x555555ebaef0,
         prog=0x555555ec3ae0, msg=0x555555ebb3e0) at rpc/virnetserver.c:165
     #11 0x00007ffff73a4e8d in virNetServerHandleJob (jobOpaque=0x555555ebc7e0, opaque=0x555555eb7e00)
         at rpc/virnetserver.c:186
     #12 0x00007ffff7187f3f in virThreadPoolWorker (opaque=0x555555eb7ac0) at util/virthreadpool.c:144
     #13 0x00007ffff718733a in virThreadHelper (data=0x555555eb7890) at util/virthreadpthread.c:161
     #14 0x00007ffff468ed89 in start_thread (arg=0x7fffec8c0700) at pthread_create.c:308
     #15 0x00007ffff3da26bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
    
    Signed-off-by: Martin Kletzander <mkletzan@redhat.com>

Index: libvirt-1.0.5.8/src/lxc/lxc_driver.c
===================================================================
--- libvirt-1.0.5.8.orig/src/lxc/lxc_driver.c
+++ libvirt-1.0.5.8/src/lxc/lxc_driver.c
@@ -819,13 +819,15 @@ lxcDomainGetMemoryParameters(virDomainPt
 {
     virLXCDriverPtr driver = dom->conn->privateData;
     int i;
+    virDomainDefPtr vmdef = NULL;
     virDomainObjPtr vm = NULL;
     unsigned long long val;
     int ret = -1;
     int rc;
     virLXCDomainObjPrivatePtr priv;
 
-    virCheckFlags(0, -1);
+    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+                  VIR_DOMAIN_AFFECT_CONFIG, -1);
 
     lxcDriverLock(driver);
     vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
@@ -839,6 +841,17 @@ lxcDomainGetMemoryParameters(virDomainPt
     }
     priv = vm->privateData;
 
+    if (virDomainLiveConfigHelperMethod(driver->caps, driver->xmlopt,
+                                        vm, &flags, &vmdef) < 0)
+        goto cleanup;
+
+    if (flags & VIR_DOMAIN_AFFECT_LIVE &&
+        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("cgroup memory controller is not mounted"));
+        goto cleanup;
+    }
+
     if ((*nparams) == 0) {
         /* Current number of memory parameters supported by cgroups */
         *nparams = LXC_NB_MEM_PARAM;
@@ -852,33 +865,48 @@ lxcDomainGetMemoryParameters(virDomainPt
 
         switch (i) {
         case 0: /* fill memory hard limit here */
-            rc = virCgroupGetMemoryHardLimit(priv->cgroup, &val);
-            if (rc != 0) {
-                virReportSystemError(-rc, "%s",
-                                     _("unable to get memory hard limit"));
-                goto cleanup;
+            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+                val = vmdef->mem.hard_limit;
+                val = val ? val : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
+            } else {
+                rc = virCgroupGetMemoryHardLimit(priv->cgroup, &val);
+                if (rc != 0) {
+                    virReportSystemError(-rc, "%s",
+                                         _("unable to get memory hard limit"));
+                    goto cleanup;
+                }
             }
             if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                         VIR_TYPED_PARAM_ULLONG, val) < 0)
                 goto cleanup;
             break;
         case 1: /* fill memory soft limit here */
-            rc = virCgroupGetMemorySoftLimit(priv->cgroup, &val);
-            if (rc != 0) {
-                virReportSystemError(-rc, "%s",
-                                     _("unable to get memory soft limit"));
-                goto cleanup;
+            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+                val = vmdef->mem.soft_limit;
+                val = val ? val : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
+            } else {
+                rc = virCgroupGetMemorySoftLimit(priv->cgroup, &val);
+                if (rc != 0) {
+                    virReportSystemError(-rc, "%s",
+                                         _("unable to get memory soft limit"));
+                    goto cleanup;
+                }
             }
             if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                         VIR_TYPED_PARAM_ULLONG, val) < 0)
                 goto cleanup;
             break;
         case 2: /* fill swap hard limit here */
-            rc = virCgroupGetMemSwapHardLimit(priv->cgroup, &val);
-            if (rc != 0) {
-                virReportSystemError(-rc, "%s",
-                                     _("unable to get swap hard limit"));
-                goto cleanup;
+            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+                val = vmdef->mem.swap_hard_limit;
+                val = val ? val : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
+            } else {
+                rc = virCgroupGetMemSwapHardLimit(priv->cgroup, &val);
+                if (rc != 0) {
+                    virReportSystemError(-rc, "%s",
+                                         _("unable to get swap hard limit"));
+                    goto cleanup;
+                }
             }
             if (virTypedParameterAssign(param,
                                         VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
