xen/9p: use alloc/free_pages_exact()
authorJuergen Gross <jgross@suse.com>
Mon, 7 Mar 2022 08:48:55 +0000 (09:48 +0100)
committerJuergen Gross <jgross@suse.com>
Mon, 7 Mar 2022 08:48:55 +0000 (09:48 +0100)
Instead of __get_free_pages() and free_pages() use alloc_pages_exact()
and free_pages_exact(). This is in preparation of a change of
gnttab_end_foreign_access() which will prohibit use of high-order
pages.

By using the local variable "order" instead of ring->intf->ring_order
in the error path of xen_9pfs_front_alloc_dataring() another bug is
fixed, as the error path can be entered before ring->intf->ring_order
is being set.

By using alloc_pages_exact() the size in bytes is specified for the
allocation, which fixes another bug for the case of
order < (PAGE_SHIFT - XEN_PAGE_SHIFT).

This is part of CVE-2022-23041 / XSA-396.

Reported-by: Simon Gaiser <simon@invisiblethingslab.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
V4:
- new patch

net/9p/trans_xen.c

index eb9fb55..01f8067 100644 (file)
@@ -281,9 +281,9 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv)
                                ref = priv->rings[i].intf->ref[j];
                                gnttab_end_foreign_access(ref, 0, 0);
                        }
-                       free_pages((unsigned long)priv->rings[i].data.in,
-                                  priv->rings[i].intf->ring_order -
-                                  (PAGE_SHIFT - XEN_PAGE_SHIFT));
+                       free_pages_exact(priv->rings[i].data.in,
+                                  1UL << (priv->rings[i].intf->ring_order +
+                                          XEN_PAGE_SHIFT));
                }
                gnttab_end_foreign_access(priv->rings[i].ref, 0, 0);
                free_page((unsigned long)priv->rings[i].intf);
@@ -322,8 +322,8 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev,
        if (ret < 0)
                goto out;
        ring->ref = ret;
-       bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
-                       order - (PAGE_SHIFT - XEN_PAGE_SHIFT));
+       bytes = alloc_pages_exact(1UL << (order + XEN_PAGE_SHIFT),
+                                 GFP_KERNEL | __GFP_ZERO);
        if (!bytes) {
                ret = -ENOMEM;
                goto out;
@@ -354,9 +354,7 @@ out:
        if (bytes) {
                for (i--; i >= 0; i--)
                        gnttab_end_foreign_access(ring->intf->ref[i], 0, 0);
-               free_pages((unsigned long)bytes,
-                          ring->intf->ring_order -
-                          (PAGE_SHIFT - XEN_PAGE_SHIFT));
+               free_pages_exact(bytes, 1UL << (order + XEN_PAGE_SHIFT));
        }
        gnttab_end_foreign_access(ring->ref, 0, 0);
        free_page((unsigned long)ring->intf);