WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-4.0-testing] tmem: disallow bad gmfns from PV domai

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-4.0-testing] tmem: disallow bad gmfns from PV domains
From: "Xen patchbot-4.0-testing" <patchbot-4.0-testing@xxxxxxxxxxxxxxxxxxx>
Date: Sun, 17 Oct 2010 05:55:20 -0700
Delivery-date: Sun, 17 Oct 2010 05:56:59 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1285142109 -3600
# Node ID 964ee203d13998fb1b246580a516bcb4d223e6b7
# Parent  b6d77507f61eb2f4158670e2ab900013837a095d
tmem: disallow bad gmfns from PV domains

Mfns for PV domains were not properly checked, potentially
allowing a buggy or malicious PV guest to crash Xen.  Also,
use get_page/put_page to claim a reference to the pages
so they can't disappear out from under tmem's feet.

Signed-off-by: Dan Magenheimer <dan.magenheimer@xxxxxxxxxx>
xen-unstable changeset:   22194:e8e3aeed3eba
xen-unstable date:        Wed Sep 22 08:54:08 2010 +0100
---
 xen/common/tmem_xen.c |  133 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 91 insertions(+), 42 deletions(-)

diff -r b6d77507f61e -r 964ee203d139 xen/common/tmem_xen.c
--- a/xen/common/tmem_xen.c     Wed Sep 22 08:49:53 2010 +0100
+++ b/xen/common/tmem_xen.c     Wed Sep 22 08:55:09 2010 +0100
@@ -87,24 +87,53 @@ void tmh_copy_page(char *to, char*from)
 }
 
 #ifdef __ia64__
-static inline void *cli_mfn_to_va(tmem_cli_mfn_t cmfn, unsigned long *pcli_mfn)
+static inline void *cli_get_page(tmem_cli_mfn_t cmfn, unsigned long *pcli_mfn,
+                                 pfp_t **pcli_pfp, bool_t cli_write)
 {
     ASSERT(0);
     return NULL;
 }
-#define paging_mark_dirty(_x,_y) do {} while(0)
+
+static inline void cli_put_page(void *cli_va, struct page_info *cli_pfp,
+                                bool_t mark_dirty)
+{
+    ASSERT(0);
+}
 #else
-static inline void *cli_mfn_to_va(tmem_cli_mfn_t cmfn, unsigned long *pcli_mfn)
+static inline void *cli_get_page(tmem_cli_mfn_t cmfn, unsigned long *pcli_mfn,
+                                 pfp_t **pcli_pfp, bool_t cli_write)
 {
     unsigned long cli_mfn;
     p2m_type_t t;
+    struct page_info *page;
+    int ret;
 
     cli_mfn = mfn_x(gfn_to_mfn(current->domain, cmfn, &t));
-    if (t != p2m_ram_rw || cli_mfn == INVALID_MFN)
-        return NULL;
-    if (pcli_mfn != NULL)
-        *pcli_mfn = cli_mfn;
+    if ( t != p2m_ram_rw || !mfn_valid(cli_mfn) )
+            return NULL;
+    page = mfn_to_page(cli_mfn);
+    if ( cli_write )
+        ret = get_page_and_type(page, current->domain, PGT_writable_page);
+    else
+        ret = get_page(page, current->domain);
+    if ( !ret )
+        return NULL;
+    *pcli_mfn = cli_mfn;
+    *pcli_pfp = (pfp_t *)page;
     return map_domain_page(cli_mfn);
+}
+
+static inline void cli_put_page(void *cli_va, pfp_t *cli_pfp,
+                                unsigned long cli_mfn, bool_t mark_dirty)
+{
+    if ( mark_dirty )
+    {
+        paging_mark_dirty(current->domain,cli_mfn);
+        put_page_and_type((struct page_info *)cli_pfp);
+    }
+    else
+        put_page((struct page_info *)cli_pfp);
+    unmap_domain_page(cli_va);
 }
 #endif
 
@@ -112,24 +141,34 @@ EXPORT int tmh_copy_from_client(pfp_t *p
     tmem_cli_mfn_t cmfn, pagesize_t tmem_offset,
     pagesize_t pfn_offset, pagesize_t len, void *cli_va)
 {
-    unsigned long tmem_mfn;
+    unsigned long tmem_mfn, cli_mfn = 0;
     void *tmem_va;
+    pfp_t *cli_pfp;
+    bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */
 
     ASSERT(pfp != NULL);
-    if ( tmem_offset || pfn_offset || len )
-        if ( (cli_va == NULL) && ((cli_va = cli_mfn_to_va(cmfn,NULL)) == NULL) 
)
-            return -EFAULT;
     tmem_mfn = page_to_mfn(pfp);
     tmem_va = map_domain_page(tmem_mfn);
-    mb();
-    if (!len && !tmem_offset && !pfn_offset)
+    if ( tmem_offset == 0 && pfn_offset == 0 && len == 0 )
+    {
         memset(tmem_va, 0, PAGE_SIZE);
-    else if (len == PAGE_SIZE && !tmem_offset && !pfn_offset)
+        unmap_domain_page(tmem_va);
+        return 1;
+    }
+    if ( !tmemc )
+    {
+        cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 0);
+        if ( cli_va == NULL )
+            return -EFAULT;
+    }
+    mb();
+    if (len == PAGE_SIZE && !tmem_offset && !pfn_offset)
         tmh_copy_page(tmem_va, cli_va);
     else if ( (tmem_offset+len <= PAGE_SIZE) &&
-                (pfn_offset+len <= PAGE_SIZE) ) 
+              (pfn_offset+len <= PAGE_SIZE) )
         memcpy((char *)tmem_va+tmem_offset,(char *)cli_va+pfn_offset,len);
-    unmap_domain_page(cli_va);
+    if ( !tmemc )
+        cli_put_page(cli_va, cli_pfp, cli_mfn, 0);
     unmap_domain_page(tmem_va);
     return 1;
 }
@@ -140,15 +179,24 @@ EXPORT int tmh_compress_from_client(tmem
     int ret = 0;
     unsigned char *dmem = this_cpu(dstmem);
     unsigned char *wmem = this_cpu(workmem);
-
-    if ( (cli_va == NULL) && (cli_va = cli_mfn_to_va(cmfn,NULL)) == NULL)
-        return -EFAULT;
+    pfp_t *cli_pfp;
+    unsigned long cli_mfn = 0;
+    bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */
+
     if ( dmem == NULL || wmem == NULL )
         return 0;  /* no buffer, so can't compress */
+    if ( !tmemc )
+    {
+        cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 0);
+        if ( cli_va == NULL )
+            return -EFAULT;
+    }
     mb();
     ret = lzo1x_1_compress(cli_va, PAGE_SIZE, dmem, out_len, wmem);
     ASSERT(ret == LZO_E_OK);
     *out_va = dmem;
+    if ( !tmemc )
+        cli_put_page(cli_va, cli_pfp, cli_mfn, 0);
     unmap_domain_page(cli_va);
     return 1;
 }
@@ -157,14 +205,17 @@ EXPORT int tmh_copy_to_client(tmem_cli_m
     pagesize_t tmem_offset, pagesize_t pfn_offset, pagesize_t len, void 
*cli_va)
 {
     unsigned long tmem_mfn, cli_mfn = 0;
-    int mark_dirty = 1;
     void *tmem_va;
+    pfp_t *cli_pfp;
+    bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */
 
     ASSERT(pfp != NULL);
-    if ( cli_va != NULL )
-        mark_dirty = 0;
-    else if ( (cli_va = cli_mfn_to_va(cmfn,&cli_mfn)) == NULL)
-        return -EFAULT;
+    if ( !tmemc )
+    {
+        cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 1);
+        if ( cli_va == NULL )
+            return -EFAULT;
+    }
     tmem_mfn = page_to_mfn(pfp);
     tmem_va = map_domain_page(tmem_mfn);
     if (len == PAGE_SIZE && !tmem_offset && !pfn_offset)
@@ -172,11 +223,8 @@ EXPORT int tmh_copy_to_client(tmem_cli_m
     else if ( (tmem_offset+len <= PAGE_SIZE) && (pfn_offset+len <= PAGE_SIZE) )
         memcpy((char *)cli_va+pfn_offset,(char *)tmem_va+tmem_offset,len);
     unmap_domain_page(tmem_va);
-    if ( mark_dirty )
-    {
-        unmap_domain_page(cli_va);
-        paging_mark_dirty(current->domain,cli_mfn);
-    }
+    if ( !tmemc )
+        cli_put_page(cli_va, cli_pfp, cli_mfn, 1);
     mb();
     return 1;
 }
@@ -185,22 +233,22 @@ EXPORT int tmh_decompress_to_client(tmem
                                     size_t size, void *cli_va)
 {
     unsigned long cli_mfn = 0;
-    int mark_dirty = 1;
+    pfp_t *cli_pfp;
     size_t out_len = PAGE_SIZE;
+    bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */
     int ret;
 
-    if ( cli_va != NULL )
-        mark_dirty = 0;
-    else if ( (cli_va = cli_mfn_to_va(cmfn,&cli_mfn)) == NULL)
-        return -EFAULT;
+    if ( !tmemc )
+    {
+        cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 1);
+        if ( cli_va == NULL )
+            return -EFAULT;
+    }
     ret = lzo1x_decompress_safe(tmem_va, size, cli_va, &out_len);
     ASSERT(ret == LZO_E_OK);
     ASSERT(out_len == PAGE_SIZE);
-    if ( mark_dirty )
-    {
-        unmap_domain_page(cli_va);
-        paging_mark_dirty(current->domain,cli_mfn);
-    }
+    if ( !tmemc )
+        cli_put_page(cli_va, cli_pfp, cli_mfn, 1);
     mb();
     return 1;
 }
@@ -210,18 +258,19 @@ EXPORT int tmh_copy_tze_to_client(tmem_c
 {
     void *cli_va;
     unsigned long cli_mfn;
+    pfp_t *cli_pfp;
 
     ASSERT(!(len & (sizeof(uint64_t)-1)));
     ASSERT(len <= PAGE_SIZE);
     ASSERT(len > 0 || tmem_va == NULL);
-    if ( (cli_va = cli_mfn_to_va(cmfn,&cli_mfn)) == NULL)
+    cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 1);
+    if ( cli_va == NULL )
         return -EFAULT;
     if ( len > 0 )
         memcpy((char *)cli_va,(char *)tmem_va,len);
     if ( len < PAGE_SIZE )
         memset((char *)cli_va+len,0,PAGE_SIZE-len);
-    unmap_domain_page(cli_va);
-    paging_mark_dirty(current->domain,cli_mfn);
+    cli_put_page(cli_va, cli_pfp, cli_mfn, 1);
     mb();
     return 1;
 }

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-4.0-testing] tmem: disallow bad gmfns from PV domains, Xen patchbot-4.0-testing <=