Index: /trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp	(revision 27117)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest.cpp	(revision 27118)
@@ -366,7 +366,8 @@
  * @returns VBox status code.
  * @param   pDevExt         The device extension.
+ * @param   pSession        The session.
  * @param   cBalloonChunks  The new size of the balloon in chunks of 1MB.
  */
-static int vboxGuestSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt, uint32_t cBalloonChunks)
+static int vboxGuestSetBalloonSizeKernel(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession, uint32_t cBalloonChunks)
 {
     int rc = VINF_SUCCESS;
@@ -483,16 +484,16 @@
     if (fInflate)
     {
-        if (   pSession->MemBalloon.cChunks > pDevExt->MemBalloon.cMaxChunks - 1
+        if (   pDevExt->MemBalloon.cChunks > pDevExt->MemBalloon.cMaxChunks - 1
             || pDevExt->MemBalloon.cMaxChunks == 0 /* If called without first querying. */)
         {
             LogRel(("vboxGuestSetBalloonSize: cannot inflate balloon, already have %u chunks (max=%u)\n",
-                    pSession->MemBalloon.cChunks, pDevExt->MemBalloon.cMaxChunks));
+                    pDevExt->MemBalloon.cChunks, pDevExt->MemBalloon.cMaxChunks));
             return VERR_INVALID_PARAMETER;
         }
 
-        if (!pSession->MemBalloon.paMemObj)
-        {
-            pSession->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAlloc(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
-            if (!pSession->MemBalloon.paMemObj)
+        if (!pDevExt->MemBalloon.paMemObj)
+        {
+            pDevExt->MemBalloon.paMemObj = (PRTR0MEMOBJ)RTMemAlloc(sizeof(RTR0MEMOBJ) * pDevExt->MemBalloon.cMaxChunks);
+            if (!pDevExt->MemBalloon.paMemObj)
             {
                 LogRel(("VBoxGuestSetBalloonSizeFromUser: no memory for paMemObj!\n"));
@@ -500,10 +501,10 @@
             }
             for (i = 0; i < pDevExt->MemBalloon.cMaxChunks; i++)
-                pSession->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
+                pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
         }
     }
     else
     {
-        if (pSession->MemBalloon.cChunks == 0)
+        if (pDevExt->MemBalloon.cChunks == 0)
         {
             AssertMsgFailed(("vboxGuestSetBalloonSize: cannot decrease balloon, already at size 0\n"));
@@ -519,11 +520,11 @@
         if (   fInflate
             && !pMemObj
-            && pSession->MemBalloon.paMemObj[i] == NIL_RTR0MEMOBJ)
-            pMemObj = &pSession->MemBalloon.paMemObj[i]; /* found free object pointer */
-        if (RTR0MemObjAddressR3(pSession->MemBalloon.paMemObj[i]) == u64ChunkAddr)
+            && pDevExt->MemBalloon.paMemObj[i] == NIL_RTR0MEMOBJ)
+            pMemObj = &pDevExt->MemBalloon.paMemObj[i]; /* found free object pointer */
+        if (RTR0MemObjAddressR3(pDevExt->MemBalloon.paMemObj[i]) == u64ChunkAddr)
         {
             if (fInflate)
                 return VERR_ALREADY_EXISTS; /* don't provide the same memory twice */
-            pMemObj = &pSession->MemBalloon.paMemObj[i];
+            pMemObj = &pDevExt->MemBalloon.paMemObj[i];
             break;
         }
@@ -532,6 +533,11 @@
     {
         if (fInflate)
-            return VERR_NO_MEMORY; /* no free object pointer found -- should not happen */
-        return VERR_NOT_FOUND; /* cannot free this memory as it wasn't provided before */
+        {
+            /* no free object pointer found -- should not happen */
+            return VERR_NO_MEMORY;
+        }
+
+        /* cannot free this memory as it wasn't provided before */
+        return VERR_NOT_FOUND;
     }
 
@@ -548,5 +554,5 @@
             rc = vboxGuestBalloonInflate(pMemObj, pReq);
             if (RT_SUCCESS(rc))
-                pSession->MemBalloon.cChunks++;
+                pDevExt->MemBalloon.cChunks++;
             else
             {
@@ -561,5 +567,5 @@
         rc = vboxGuestBalloonDeflate(pMemObj, pReq);
         if (RT_SUCCESS(rc))
-            pSession->MemBalloon.cChunks--;
+            pDevExt->MemBalloon.cChunks--;
         else
             Log(("vboxGuestSetBalloonSize(deflate): failed, rc=%Rrc!\n", rc));
@@ -573,8 +579,15 @@
 /**
  * Cleanup the memory balloon of a session.
- */
-static void vboxGuestCloseSessionMemBalloon(PVBOXGUESTSESSION pSession)
-{
-    if (pSession->MemBalloon.paMemObj)
+ *
+ * @param   pDevExt     The device extension.
+ * @param   pDevExt     The session. Can be NULL if no owner check required.
+ */
+static void vboxGuestCloseMemBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession)
+{
+    if (   pSession != (PVBOXGUESTSESSION)NULL
+        && ASMAtomicReadPtr((void * volatile *)&pDevExt->MemBalloon.pOwner) != pSession)
+        return;
+
+    if (pDevExt->MemBalloon.paMemObj)
     {
         VMMDevChangeMemBalloon *pReq;
@@ -583,7 +596,7 @@
         {
             uint32_t i;
-            for (i = pSession->MemBalloon.cChunks; i-- > 0;)
+            for (i = pDevExt->MemBalloon.cChunks; i-- > 0;)
             {
-                rc = vboxGuestBalloonDeflate(&pSession->MemBalloon.paMemObj[i], pReq);
+                rc = vboxGuestBalloonDeflate(&pDevExt->MemBalloon.paMemObj[i], pReq);
                 if (RT_FAILURE(rc))
                 {
@@ -591,17 +604,19 @@
                     break;
                 }
-                pSession->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
-                pSession->MemBalloon.cChunks--;
+                pDevExt->MemBalloon.paMemObj[i] = NIL_RTR0MEMOBJ;
+                pDevExt->MemBalloon.cChunks--;
             }
             VbglGRFree(&pReq->header);
         }
-        RTMemFree(pSession->MemBalloon.paMemObj);
-        pSession->MemBalloon.paMemObj = NULL;
-    }
-}
-
-
-/**
- * Init the variables for memory ballooning
+        RTMemFree(pDevExt->MemBalloon.paMemObj);
+        pDevExt->MemBalloon.paMemObj = NULL;
+    }
+
+    ASMAtomicWritePtr((void * volatile *)&pDevExt->MemBalloon.pOwner, NULL);
+}
+
+
+/**
+ * Init the variables for memory ballooning.
  *
  * @param   pDevExt     The device extension
@@ -613,20 +628,5 @@
     pDevExt->MemBalloon.fUseKernelAPI = true;
     pDevExt->MemBalloon.paMemObj = NULL;
-}
-
-
-/**
- * Finish memory ballooning, reclaim all memory from the host.
- *
- * @param   pDevExt     The device extension
- */
-static void vboxGuestDoneMemBalloon(PVBOXGUESTDEVEXT pDevExt)
-{
-    if (pDevExt->MemBalloon.paMemObj)
-    {
-        vboxGuestSetBalloonSizeKernel(pDevExt, 0);
-        RTMemFree(pDevExt->MemBalloon.paMemObj);
-        pDevExt->MemBalloon.paMemObj = NULL;
-    }
+    ASMAtomicWritePtr((void * volatile *)&pDevExt->MemBalloon.pOwner, NULL);
 }
 
@@ -822,5 +822,5 @@
     VBoxGuestSetGuestCapabilities(0, UINT32_MAX);
     vboxGuestSetFilterMask(pDevExt, 0);
-    vboxGuestDoneMemBalloon(pDevExt);
+    vboxGuestCloseMemBalloon(pDevExt, (PVBOXGUESTSESSION)NULL);
 
     /*
@@ -867,7 +867,4 @@
     pSession->R0Process = RTR0ProcHandleSelf();
     pSession->pDevExt = pDevExt;
-
-    pSession->MemBalloon.cChunks = 0;
-    pSession->MemBalloon.cMaxChunks = 0;
 
     *ppSession = pSession;
@@ -937,5 +934,5 @@
     pSession->Process = NIL_RTPROCESS;
     pSession->R0Process = NIL_RTR0PROCESS;
-    vboxGuestCloseSessionMemBalloon(pSession);
+    vboxGuestCloseMemBalloon(pDevExt, pSession);
     RTMemFree(pSession);
 }
@@ -1845,19 +1842,26 @@
  *
  * @param   pDevExt             The device extension.
+ * @param   pSession            The session.
  * @param   pInfo               The output buffer.
  * @param   pcbDataReturned     Where to store the amount of returned data. Can
  *                              be NULL.
  */
-static int VBoxGuestCommonIOCtl_QueryMemoryBalloon(PVBOXGUESTDEVEXT pDevExt,
+static int VBoxGuestCommonIOCtl_QueryMemoryBalloon(PVBOXGUESTDEVEXT pDevExt, PVBOXGUESTSESSION pSession,
                                                    VBoxGuestCheckBalloonInfo *pInfo, size_t *pcbDataReturned)
 {
     VMMDevGetMemBalloonChangeRequest *pReq;
+    PVBOXGUESTSESSION pOwner;
+    int rc;
+
     Log(("VBoxGuestCommonIOCtl: QUERYMEMORYBALLOON\n"));
-    int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevGetMemBalloonChangeRequest), VMMDevReq_GetMemBalloonChangeRequest);
+    /* the first user trying to query/change the balloon is the owner */
+    if (   !ASMAtomicCmpXchgExPtr((void * volatile *)&pDevExt->MemBalloon.pOwner, (const void*) pSession,
+                                   (PVBOXGUESTSESSION)NULL, (void**)&pOwner)
+        && pOwner != pSession)
+        return VERR_PERMISSION_DENIED;
+
+    rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(VMMDevGetMemBalloonChangeRequest), VMMDevReq_GetMemBalloonChangeRequest);
     if (RT_FAILURE(rc))
         return rc;
-
-/** @todo r=bird: The following needs to be serialized as there is no one
- *        saying mr. evil user cannot start more than one VBoxService. */
 
     /* This is a response to that event. Setting this bit means that we request the value
@@ -1875,5 +1879,5 @@
     pDevExt->MemBalloon.cMaxChunks = pReq->cPhysMemChunks;
 
-    rc = vboxGuestSetBalloonSizeKernel(pDevExt, pReq->cBalloonChunks);
+    rc = vboxGuestSetBalloonSizeKernel(pDevExt, pSession, pReq->cBalloonChunks);
     /* Ignore out of memory failures */
     if (rc == VERR_NO_MEMORY)
@@ -1888,4 +1892,6 @@
         rc = VINF_SUCCESS;
     }
+
+    VbglGRFree(&pReq->header);
 
     if (pcbDataReturned)
@@ -1911,14 +1917,17 @@
                                                     VBoxGuestChangeBalloonInfo *pInfo, size_t *pcbDataReturned)
 {
-/** @todo r=bird: Don't allow this if fUseKernelAPI is true.  */
-/** @todo r=bird: This needs to be serialized as there is no one saying mr. evil
- *        user cannot start more than one VBoxService.
- *
- *        Actually, it would be good to drop the VBOXGUESTSESSION::MemBalloon
- *        and instead add a VBOXGUESTDEVEXT::pMemBallonOwner
- *        (PVBOXGUESTSESSION).  Assign balloon ownership on a first come
- *        basis, releasing it when the session quits.  This could be done
- *        regardless of the method use for memory allocation. */
-    int rc = vboxGuestSetBalloonSizeFromUser(pDevExt, pSession, pInfo->u64ChunkAddr, pInfo->fInflate);
+    int rc;
+    PVBOXGUESTSESSION pOwner;
+
+    if (pDevExt->MemBalloon.fUseKernelAPI)
+        return VERR_PERMISSION_DENIED;
+
+    /* the first user trying to query/change the balloon is the owner */
+    if (   !ASMAtomicCmpXchgExPtr((void * volatile *)&pDevExt->MemBalloon.pOwner, (const void*) pSession,
+                                   (PVBOXGUESTSESSION)NULL, (void**)&pOwner)
+        && pOwner != pSession)
+        return VERR_PERMISSION_DENIED;
+
+    rc = vboxGuestSetBalloonSizeFromUser(pDevExt, pSession, pInfo->u64ChunkAddr, pInfo->fInflate);
     if (pcbDataReturned)
         *pcbDataReturned = 0;
@@ -2109,5 +2118,5 @@
             case VBOXGUEST_IOCTL_CHECK_BALLOON:
                 CHECKRET_MIN_SIZE("CHECK_MEMORY_BALLOON", sizeof(VBoxGuestCheckBalloonInfo));
-                rc = VBoxGuestCommonIOCtl_QueryMemoryBalloon(pDevExt, (VBoxGuestCheckBalloonInfo *)pvData, pcbDataReturned);
+                rc = VBoxGuestCommonIOCtl_QueryMemoryBalloon(pDevExt, pSession, (VBoxGuestCheckBalloonInfo *)pvData, pcbDataReturned);
                 break;
 
Index: /trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h	(revision 27117)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuestInternal.h	(revision 27118)
@@ -90,4 +90,6 @@
      * and false otherwise. */
     bool                        fUseKernelAPI;
+    /** The owner of the balloon which is the first process using the balloon API. */
+    PVBOXGUESTSESSION volatile  pOwner;
     /** The pointer to the array of memory objects holding the chunks of the
      *  balloon.  This array is cMaxChunks in size when present. */
@@ -186,6 +188,4 @@
     uint32_t volatile           u32MousePosChangedSeq;
 
-    /* Memory ballooning information if userland provides the balloon memory. */
-    VBOXGUESTMEMBALLOON         MemBalloon;
 } VBOXGUESTSESSION;
 
