]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Mar 2022 13:41:44 +0000 (14:41 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Mar 2022 13:41:44 +0000 (14:41 +0100)
added patches:
xen-9p-use-alloc-free_pages_exact.patch
xen-blkfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
xen-gntalloc-don-t-use-gnttab_query_foreign_access.patch
xen-gnttab-fix-gnttab_end_foreign_access-without-page-specified.patch
xen-grant-table-add-gnttab_try_end_foreign_access.patch
xen-netfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
xen-netfront-react-properly-to-failing-gnttab_end_foreign_access_ref.patch
xen-remove-gnttab_query_foreign_access.patch
xen-scsifront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
xen-xenbus-don-t-let-xenbus_grant_ring-remove-grants-in-error-case.patch

queue-4.14/series
queue-4.14/xen-9p-use-alloc-free_pages_exact.patch [new file with mode: 0644]
queue-4.14/xen-blkfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch [new file with mode: 0644]
queue-4.14/xen-gntalloc-don-t-use-gnttab_query_foreign_access.patch [new file with mode: 0644]
queue-4.14/xen-gnttab-fix-gnttab_end_foreign_access-without-page-specified.patch [new file with mode: 0644]
queue-4.14/xen-grant-table-add-gnttab_try_end_foreign_access.patch [new file with mode: 0644]
queue-4.14/xen-netfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch [new file with mode: 0644]
queue-4.14/xen-netfront-react-properly-to-failing-gnttab_end_foreign_access_ref.patch [new file with mode: 0644]
queue-4.14/xen-remove-gnttab_query_foreign_access.patch [new file with mode: 0644]
queue-4.14/xen-scsifront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch [new file with mode: 0644]
queue-4.14/xen-xenbus-don-t-let-xenbus_grant_ring-remove-grants-in-error-case.patch [new file with mode: 0644]

index 0d55391d4eaed1c73887dc6a9207e533491c1803..fe9711016e0e4779edfc838826471b07add810e0 100644 (file)
@@ -19,3 +19,13 @@ arm-fix-build-error-when-bpf_syscall-is-disabled.patch
 arm-fix-co-processor-register-typo.patch
 arm-do-not-use-nocrossrefs-directive-with-ld.lld.patch
 arm-fix-build-warning-in-proc-v7-bugs.c.patch
+xen-xenbus-don-t-let-xenbus_grant_ring-remove-grants-in-error-case.patch
+xen-grant-table-add-gnttab_try_end_foreign_access.patch
+xen-blkfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
+xen-netfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
+xen-scsifront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
+xen-gntalloc-don-t-use-gnttab_query_foreign_access.patch
+xen-remove-gnttab_query_foreign_access.patch
+xen-9p-use-alloc-free_pages_exact.patch
+xen-gnttab-fix-gnttab_end_foreign_access-without-page-specified.patch
+xen-netfront-react-properly-to-failing-gnttab_end_foreign_access_ref.patch
diff --git a/queue-4.14/xen-9p-use-alloc-free_pages_exact.patch b/queue-4.14/xen-9p-use-alloc-free_pages_exact.patch
new file mode 100644 (file)
index 0000000..af7e8c4
--- /dev/null
@@ -0,0 +1,70 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:42 +0100
+Subject: xen/9p: use alloc/free_pages_exact()
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 5cadd4bb1d7fc9ab201ac14620d1a478357e4ebd upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/9p/trans_xen.c |   14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+--- a/net/9p/trans_xen.c
++++ b/net/9p/trans_xen.c
+@@ -301,9 +301,9 @@ static void xen_9pfs_front_free(struct x
+                               ref = priv->rings[i].intf->ref[j];
+                               gnttab_end_foreign_access(ref, 0, 0);
+                       }
+-                      free_pages((unsigned long)priv->rings[i].data.in,
+-                                 XEN_9PFS_RING_ORDER -
+-                                 (PAGE_SHIFT - XEN_PAGE_SHIFT));
++                      free_pages_exact(priv->rings[i].data.in,
++                                 1UL << (XEN_9PFS_RING_ORDER +
++                                         XEN_PAGE_SHIFT));
+               }
+               gnttab_end_foreign_access(priv->rings[i].ref, 0, 0);
+               free_page((unsigned long)priv->rings[i].intf);
+@@ -341,8 +341,8 @@ static int xen_9pfs_front_alloc_dataring
+       if (ret < 0)
+               goto out;
+       ring->ref = ret;
+-      bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+-                      XEN_9PFS_RING_ORDER - (PAGE_SHIFT - XEN_PAGE_SHIFT));
++      bytes = alloc_pages_exact(1UL << (XEN_9PFS_RING_ORDER + XEN_PAGE_SHIFT),
++                                GFP_KERNEL | __GFP_ZERO);
+       if (!bytes) {
+               ret = -ENOMEM;
+               goto out;
+@@ -373,9 +373,7 @@ out:
+       if (bytes) {
+               for (i--; i >= 0; i--)
+                       gnttab_end_foreign_access(ring->intf->ref[i], 0, 0);
+-              free_pages((unsigned long)bytes,
+-                         XEN_9PFS_RING_ORDER -
+-                         (PAGE_SHIFT - XEN_PAGE_SHIFT));
++              free_pages_exact(bytes, 1UL << (XEN_9PFS_RING_ORDER + XEN_PAGE_SHIFT));
+       }
+       gnttab_end_foreign_access(ring->ref, 0, 0);
+       free_page((unsigned long)ring->intf);
diff --git a/queue-4.14/xen-blkfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch b/queue-4.14/xen-blkfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
new file mode 100644 (file)
index 0000000..b624159
--- /dev/null
@@ -0,0 +1,183 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:41 +0100
+Subject: xen/blkfront: don't use gnttab_query_foreign_access() for mapped status
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit abf1fd5919d6238ee3bc5eb4a9b6c3947caa6638 upstream.
+
+It isn't enough to check whether a grant is still being in use by
+calling gnttab_query_foreign_access(), as a mapping could be realized
+by the other side just after having called that function.
+
+In case the call was done in preparation of revoking a grant it is
+better to do so via gnttab_end_foreign_access_ref() and check the
+success of that operation instead.
+
+For the ring allocation use alloc_pages_exact() in order to avoid
+high order pages in case of a multi-page ring.
+
+If a grant wasn't unmapped by the backend without persistent grants
+being used, set the device state to "error".
+
+This is CVE-2022-23036 / part of XSA-396.
+
+Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Roger Pau MonnĂ© <roger.pau@citrix.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/xen-blkfront.c |   67 +++++++++++++++++++++++++------------------
+ 1 file changed, 39 insertions(+), 28 deletions(-)
+
+--- a/drivers/block/xen-blkfront.c
++++ b/drivers/block/xen-blkfront.c
+@@ -1278,17 +1278,16 @@ static void blkif_free_ring(struct blkfr
+               list_for_each_entry_safe(persistent_gnt, n,
+                                        &rinfo->grants, node) {
+                       list_del(&persistent_gnt->node);
+-                      if (persistent_gnt->gref != GRANT_INVALID_REF) {
+-                              gnttab_end_foreign_access(persistent_gnt->gref,
+-                                                        0, 0UL);
+-                              rinfo->persistent_gnts_c--;
+-                      }
++                      if (persistent_gnt->gref == GRANT_INVALID_REF ||
++                          !gnttab_try_end_foreign_access(persistent_gnt->gref))
++                              continue;
++
++                      rinfo->persistent_gnts_c--;
+                       if (info->feature_persistent)
+                               __free_page(persistent_gnt->page);
+                       kfree(persistent_gnt);
+               }
+       }
+-      BUG_ON(rinfo->persistent_gnts_c != 0);
+       for (i = 0; i < BLK_RING_SIZE(info); i++) {
+               /*
+@@ -1345,7 +1344,8 @@ free_shadow:
+                       rinfo->ring_ref[i] = GRANT_INVALID_REF;
+               }
+       }
+-      free_pages((unsigned long)rinfo->ring.sring, get_order(info->nr_ring_pages * XEN_PAGE_SIZE));
++      free_pages_exact(rinfo->ring.sring,
++                       info->nr_ring_pages * XEN_PAGE_SIZE);
+       rinfo->ring.sring = NULL;
+       if (rinfo->irq)
+@@ -1429,9 +1429,15 @@ static int blkif_get_final_status(enum b
+       return BLKIF_RSP_OKAY;
+ }
+-static bool blkif_completion(unsigned long *id,
+-                           struct blkfront_ring_info *rinfo,
+-                           struct blkif_response *bret)
++/*
++ * Return values:
++ *  1 response processed.
++ *  0 missing further responses.
++ * -1 error while processing.
++ */
++static int blkif_completion(unsigned long *id,
++                          struct blkfront_ring_info *rinfo,
++                          struct blkif_response *bret)
+ {
+       int i = 0;
+       struct scatterlist *sg;
+@@ -1505,42 +1511,43 @@ static bool blkif_completion(unsigned lo
+       }
+       /* Add the persistent grant into the list of free grants */
+       for (i = 0; i < num_grant; i++) {
+-              if (gnttab_query_foreign_access(s->grants_used[i]->gref)) {
++              if (!gnttab_try_end_foreign_access(s->grants_used[i]->gref)) {
+                       /*
+                        * If the grant is still mapped by the backend (the
+                        * backend has chosen to make this grant persistent)
+                        * we add it at the head of the list, so it will be
+                        * reused first.
+                        */
+-                      if (!info->feature_persistent)
+-                              pr_alert_ratelimited("backed has not unmapped grant: %u\n",
+-                                                   s->grants_used[i]->gref);
++                      if (!info->feature_persistent) {
++                              pr_alert("backed has not unmapped grant: %u\n",
++                                       s->grants_used[i]->gref);
++                              return -1;
++                      }
+                       list_add(&s->grants_used[i]->node, &rinfo->grants);
+                       rinfo->persistent_gnts_c++;
+               } else {
+                       /*
+-                       * If the grant is not mapped by the backend we end the
+-                       * foreign access and add it to the tail of the list,
+-                       * so it will not be picked again unless we run out of
+-                       * persistent grants.
++                       * If the grant is not mapped by the backend we add it
++                       * to the tail of the list, so it will not be picked
++                       * again unless we run out of persistent grants.
+                        */
+-                      gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
+                       s->grants_used[i]->gref = GRANT_INVALID_REF;
+                       list_add_tail(&s->grants_used[i]->node, &rinfo->grants);
+               }
+       }
+       if (s->req.operation == BLKIF_OP_INDIRECT) {
+               for (i = 0; i < INDIRECT_GREFS(num_grant); i++) {
+-                      if (gnttab_query_foreign_access(s->indirect_grants[i]->gref)) {
+-                              if (!info->feature_persistent)
+-                                      pr_alert_ratelimited("backed has not unmapped grant: %u\n",
+-                                                           s->indirect_grants[i]->gref);
++                      if (!gnttab_try_end_foreign_access(s->indirect_grants[i]->gref)) {
++                              if (!info->feature_persistent) {
++                                      pr_alert("backed has not unmapped grant: %u\n",
++                                               s->indirect_grants[i]->gref);
++                                      return -1;
++                              }
+                               list_add(&s->indirect_grants[i]->node, &rinfo->grants);
+                               rinfo->persistent_gnts_c++;
+                       } else {
+                               struct page *indirect_page;
+-                              gnttab_end_foreign_access(s->indirect_grants[i]->gref, 0, 0UL);
+                               /*
+                                * Add the used indirect page back to the list of
+                                * available pages for indirect grefs.
+@@ -1621,12 +1628,17 @@ static irqreturn_t blkif_interrupt(int i
+               }
+               if (bret.operation != BLKIF_OP_DISCARD) {
++                      int ret;
++
+                       /*
+                        * We may need to wait for an extra response if the
+                        * I/O request is split in 2
+                        */
+-                      if (!blkif_completion(&id, rinfo, &bret))
++                      ret = blkif_completion(&id, rinfo, &bret);
++                      if (!ret)
+                               continue;
++                      if (unlikely(ret < 0))
++                              goto err;
+               }
+               if (add_id_to_freelist(rinfo, id)) {
+@@ -1732,8 +1744,7 @@ static int setup_blkring(struct xenbus_d
+       for (i = 0; i < info->nr_ring_pages; i++)
+               rinfo->ring_ref[i] = GRANT_INVALID_REF;
+-      sring = (struct blkif_sring *)__get_free_pages(GFP_NOIO | __GFP_HIGH,
+-                                                     get_order(ring_size));
++      sring = alloc_pages_exact(ring_size, GFP_NOIO);
+       if (!sring) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+               return -ENOMEM;
+@@ -1743,7 +1754,7 @@ static int setup_blkring(struct xenbus_d
+       err = xenbus_grant_ring(dev, rinfo->ring.sring, info->nr_ring_pages, gref);
+       if (err < 0) {
+-              free_pages((unsigned long)sring, get_order(ring_size));
++              free_pages_exact(sring, ring_size);
+               rinfo->ring.sring = NULL;
+               goto fail;
+       }
diff --git a/queue-4.14/xen-gntalloc-don-t-use-gnttab_query_foreign_access.patch b/queue-4.14/xen-gntalloc-don-t-use-gnttab_query_foreign_access.patch
new file mode 100644 (file)
index 0000000..1095eff
--- /dev/null
@@ -0,0 +1,79 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:42 +0100
+Subject: xen/gntalloc: don't use gnttab_query_foreign_access()
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit d3b6372c5881cb54925212abb62c521df8ba4809 upstream.
+
+Using gnttab_query_foreign_access() is unsafe, as it is racy by design.
+
+The use case in the gntalloc driver is not needed at all. While at it
+replace the call of gnttab_end_foreign_access_ref() with a call of
+gnttab_end_foreign_access(), which is what is really wanted there. In
+case the grant wasn't used due to an allocation failure, just free the
+grant via gnttab_free_grant_reference().
+
+This is CVE-2022-23039 / part of XSA-396.
+
+Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/gntalloc.c |   25 +++++++------------------
+ 1 file changed, 7 insertions(+), 18 deletions(-)
+
+--- a/drivers/xen/gntalloc.c
++++ b/drivers/xen/gntalloc.c
+@@ -169,20 +169,14 @@ undo:
+               __del_gref(gref);
+       }
+-      /* It's possible for the target domain to map the just-allocated grant
+-       * references by blindly guessing their IDs; if this is done, then
+-       * __del_gref will leave them in the queue_gref list. They need to be
+-       * added to the global list so that we can free them when they are no
+-       * longer referenced.
+-       */
+-      if (unlikely(!list_empty(&queue_gref)))
+-              list_splice_tail(&queue_gref, &gref_list);
+       mutex_unlock(&gref_mutex);
+       return rc;
+ }
+ static void __del_gref(struct gntalloc_gref *gref)
+ {
++      unsigned long addr;
++
+       if (gref->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
+               uint8_t *tmp = kmap(gref->page);
+               tmp[gref->notify.pgoff] = 0;
+@@ -196,21 +190,16 @@ static void __del_gref(struct gntalloc_g
+       gref->notify.flags = 0;
+       if (gref->gref_id) {
+-              if (gnttab_query_foreign_access(gref->gref_id))
+-                      return;
+-
+-              if (!gnttab_end_foreign_access_ref(gref->gref_id, 0))
+-                      return;
+-
+-              gnttab_free_grant_reference(gref->gref_id);
++              if (gref->page) {
++                      addr = (unsigned long)page_to_virt(gref->page);
++                      gnttab_end_foreign_access(gref->gref_id, 0, addr);
++              } else
++                      gnttab_free_grant_reference(gref->gref_id);
+       }
+       gref_size--;
+       list_del(&gref->next_gref);
+-      if (gref->page)
+-              __free_page(gref->page);
+-
+       kfree(gref);
+ }
diff --git a/queue-4.14/xen-gnttab-fix-gnttab_end_foreign_access-without-page-specified.patch b/queue-4.14/xen-gnttab-fix-gnttab_end_foreign_access-without-page-specified.patch
new file mode 100644 (file)
index 0000000..9e5c96d
--- /dev/null
@@ -0,0 +1,122 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:43 +0100
+Subject: xen/gnttab: fix gnttab_end_foreign_access() without page specified
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 42baefac638f06314298087394b982ead9ec444b upstream.
+
+gnttab_end_foreign_access() is used to free a grant reference and
+optionally to free the associated page. In case the grant is still in
+use by the other side processing is being deferred. This leads to a
+problem in case no page to be freed is specified by the caller: the
+caller doesn't know that the page is still mapped by the other side
+and thus should not be used for other purposes.
+
+The correct way to handle this situation is to take an additional
+reference to the granted page in case handling is being deferred and
+to drop that reference when the grant reference could be freed
+finally.
+
+This requires that there are no users of gnttab_end_foreign_access()
+left directly repurposing the granted page after the call, as this
+might result in clobbered data or information leaks via the not yet
+freed grant reference.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/grant-table.c |   30 +++++++++++++++++++++++-------
+ include/xen/grant_table.h |    7 ++++++-
+ 2 files changed, 29 insertions(+), 8 deletions(-)
+
+--- a/drivers/xen/grant-table.c
++++ b/drivers/xen/grant-table.c
+@@ -114,6 +114,10 @@ struct gnttab_ops {
+        * return the frame.
+        */
+       unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref);
++      /*
++       * Read the frame number related to a given grant reference.
++       */
++      unsigned long (*read_frame)(grant_ref_t ref);
+ };
+ struct unmap_refs_callback_data {
+@@ -278,6 +282,11 @@ int gnttab_end_foreign_access_ref(grant_
+ }
+ EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
++static unsigned long gnttab_read_frame_v1(grant_ref_t ref)
++{
++      return gnttab_shared.v1[ref].frame;
++}
++
+ struct deferred_entry {
+       struct list_head list;
+       grant_ref_t ref;
+@@ -307,12 +316,9 @@ static void gnttab_handle_deferred(unsig
+               spin_unlock_irqrestore(&gnttab_list_lock, flags);
+               if (_gnttab_end_foreign_access_ref(entry->ref, entry->ro)) {
+                       put_free_entry(entry->ref);
+-                      if (entry->page) {
+-                              pr_debug("freeing g.e. %#x (pfn %#lx)\n",
+-                                       entry->ref, page_to_pfn(entry->page));
+-                              put_page(entry->page);
+-                      } else
+-                              pr_info("freeing g.e. %#x\n", entry->ref);
++                      pr_debug("freeing g.e. %#x (pfn %#lx)\n",
++                               entry->ref, page_to_pfn(entry->page));
++                      put_page(entry->page);
+                       kfree(entry);
+                       entry = NULL;
+               } else {
+@@ -337,9 +343,18 @@ static void gnttab_handle_deferred(unsig
+ static void gnttab_add_deferred(grant_ref_t ref, bool readonly,
+                               struct page *page)
+ {
+-      struct deferred_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
++      struct deferred_entry *entry;
++      gfp_t gfp = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+       const char *what = KERN_WARNING "leaking";
++      entry = kmalloc(sizeof(*entry), gfp);
++      if (!page) {
++              unsigned long gfn = gnttab_interface->read_frame(ref);
++
++              page = pfn_to_page(gfn_to_pfn(gfn));
++              get_page(page);
++      }
++
+       if (entry) {
+               unsigned long flags;
+@@ -1011,6 +1026,7 @@ static const struct gnttab_ops gnttab_v1
+       .update_entry                   = gnttab_update_entry_v1,
+       .end_foreign_access_ref         = gnttab_end_foreign_access_ref_v1,
+       .end_foreign_transfer_ref       = gnttab_end_foreign_transfer_ref_v1,
++      .read_frame                     = gnttab_read_frame_v1,
+ };
+ static void gnttab_request_version(void)
+--- a/include/xen/grant_table.h
++++ b/include/xen/grant_table.h
+@@ -100,7 +100,12 @@ int gnttab_end_foreign_access_ref(grant_
+  * Note that the granted page might still be accessed (read or write) by the
+  * other side after gnttab_end_foreign_access() returns, so even if page was
+  * specified as 0 it is not allowed to just reuse the page for other
+- * purposes immediately.
++ * purposes immediately. gnttab_end_foreign_access() will take an additional
++ * reference to the granted page in this case, which is dropped only after
++ * the grant is no longer in use.
++ * This requires that multi page allocations for areas subject to
++ * gnttab_end_foreign_access() are done via alloc_pages_exact() (and freeing
++ * via free_pages_exact()) in order to avoid high order pages.
+  */
+ void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+                              unsigned long page);
diff --git a/queue-4.14/xen-grant-table-add-gnttab_try_end_foreign_access.patch b/queue-4.14/xen-grant-table-add-gnttab_try_end_foreign_access.patch
new file mode 100644 (file)
index 0000000..adbf00a
--- /dev/null
@@ -0,0 +1,79 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:41 +0100
+Subject: xen/grant-table: add gnttab_try_end_foreign_access()
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 6b1775f26a2da2b05a6dc8ec2b5d14e9a4701a1a upstream.
+
+Add a new grant table function gnttab_try_end_foreign_access(), which
+will remove and free a grant if it is not in use.
+
+Its main use case is to either free a grant if it is no longer in use,
+or to take some other action if it is still in use. This other action
+can be an error exit, or (e.g. in the case of blkfront persistent grant
+feature) some special handling.
+
+This is CVE-2022-23036, CVE-2022-23038 / part of XSA-396.
+
+Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/grant-table.c |   14 ++++++++++++--
+ include/xen/grant_table.h |   12 ++++++++++++
+ 2 files changed, 24 insertions(+), 2 deletions(-)
+
+--- a/drivers/xen/grant-table.c
++++ b/drivers/xen/grant-table.c
+@@ -378,11 +378,21 @@ static void gnttab_add_deferred(grant_re
+              what, ref, page ? page_to_pfn(page) : -1);
+ }
++int gnttab_try_end_foreign_access(grant_ref_t ref)
++{
++      int ret = _gnttab_end_foreign_access_ref(ref, 0);
++
++      if (ret)
++              put_free_entry(ref);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(gnttab_try_end_foreign_access);
++
+ void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+                              unsigned long page)
+ {
+-      if (gnttab_end_foreign_access_ref(ref, readonly)) {
+-              put_free_entry(ref);
++      if (gnttab_try_end_foreign_access(ref)) {
+               if (page != 0)
+                       put_page(virt_to_page(page));
+       } else
+--- a/include/xen/grant_table.h
++++ b/include/xen/grant_table.h
+@@ -97,10 +97,22 @@ int gnttab_end_foreign_access_ref(grant_
+  * access has been ended, free the given page too.  Access will be ended
+  * immediately iff the grant entry is not in use, otherwise it will happen
+  * some time later.  page may be 0, in which case no freeing will occur.
++ * Note that the granted page might still be accessed (read or write) by the
++ * other side after gnttab_end_foreign_access() returns, so even if page was
++ * specified as 0 it is not allowed to just reuse the page for other
++ * purposes immediately.
+  */
+ void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+                              unsigned long page);
++/*
++ * End access through the given grant reference, iff the grant entry is
++ * no longer in use.  In case of success ending foreign access, the
++ * grant reference is deallocated.
++ * Return 1 if the grant entry was freed, 0 if it is still in use.
++ */
++int gnttab_try_end_foreign_access(grant_ref_t ref);
++
+ int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
+ unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
diff --git a/queue-4.14/xen-netfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch b/queue-4.14/xen-netfront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
new file mode 100644 (file)
index 0000000..0b7b875
--- /dev/null
@@ -0,0 +1,46 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:41 +0100
+Subject: xen/netfront: don't use gnttab_query_foreign_access() for mapped status
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 31185df7e2b1d2fa1de4900247a12d7b9c7087eb upstream.
+
+It isn't enough to check whether a grant is still being in use by
+calling gnttab_query_foreign_access(), as a mapping could be realized
+by the other side just after having called that function.
+
+In case the call was done in preparation of revoking a grant it is
+better to do so via gnttab_end_foreign_access_ref() and check the
+success of that operation instead.
+
+This is CVE-2022-23037 / part of XSA-396.
+
+Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/xen-netfront.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/xen-netfront.c
++++ b/drivers/net/xen-netfront.c
+@@ -414,14 +414,12 @@ static bool xennet_tx_buf_gc(struct netf
+                       queue->tx_link[id] = TX_LINK_NONE;
+                       skb = queue->tx_skbs[id];
+                       queue->tx_skbs[id] = NULL;
+-                      if (unlikely(gnttab_query_foreign_access(
+-                              queue->grant_tx_ref[id]) != 0)) {
++                      if (unlikely(!gnttab_end_foreign_access_ref(
++                              queue->grant_tx_ref[id], GNTMAP_readonly))) {
+                               dev_alert(dev,
+                                         "Grant still in use by backend domain\n");
+                               goto err;
+                       }
+-                      gnttab_end_foreign_access_ref(
+-                              queue->grant_tx_ref[id], GNTMAP_readonly);
+                       gnttab_release_grant_reference(
+                               &queue->gref_tx_head, queue->grant_tx_ref[id]);
+                       queue->grant_tx_ref[id] = GRANT_INVALID_REF;
diff --git a/queue-4.14/xen-netfront-react-properly-to-failing-gnttab_end_foreign_access_ref.patch b/queue-4.14/xen-netfront-react-properly-to-failing-gnttab_end_foreign_access_ref.patch
new file mode 100644 (file)
index 0000000..8cb5fd1
--- /dev/null
@@ -0,0 +1,139 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:43 +0100
+Subject: xen/netfront: react properly to failing gnttab_end_foreign_access_ref()
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 66e3531b33ee51dad17c463b4d9c9f52e341503d upstream.
+
+When calling gnttab_end_foreign_access_ref() the returned value must
+be tested and the reaction to that value should be appropriate.
+
+In case of failure in xennet_get_responses() the reaction should not be
+to crash the system, but to disable the network device.
+
+The calls in setup_netfront() can be replaced by calls of
+gnttab_end_foreign_access(). While at it avoid double free of ring
+pages and grant references via xennet_disconnect_backend() in this case.
+
+This is CVE-2022-23042 / part of XSA-396.
+
+Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/xen-netfront.c |   48 +++++++++++++++++++++++++++++----------------
+ 1 file changed, 31 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/xen-netfront.c
++++ b/drivers/net/xen-netfront.c
+@@ -839,7 +839,6 @@ static int xennet_get_responses(struct n
+       int max = XEN_NETIF_NR_SLOTS_MIN + (rx->status <= RX_COPY_THRESHOLD);
+       int slots = 1;
+       int err = 0;
+-      unsigned long ret;
+       if (rx->flags & XEN_NETRXF_extra_info) {
+               err = xennet_get_extras(queue, extras, rp);
+@@ -870,8 +869,13 @@ static int xennet_get_responses(struct n
+                       goto next;
+               }
+-              ret = gnttab_end_foreign_access_ref(ref, 0);
+-              BUG_ON(!ret);
++              if (!gnttab_end_foreign_access_ref(ref, 0)) {
++                      dev_alert(dev,
++                                "Grant still in use by backend domain\n");
++                      queue->info->broken = true;
++                      dev_alert(dev, "Disabled for further use\n");
++                      return -EINVAL;
++              }
+               gnttab_release_grant_reference(&queue->gref_rx_head, ref);
+@@ -1075,6 +1079,10 @@ static int xennet_poll(struct napi_struc
+               err = xennet_get_responses(queue, &rinfo, rp, &tmpq);
+               if (unlikely(err)) {
++                      if (queue->info->broken) {
++                              spin_unlock(&queue->rx_lock);
++                              return 0;
++                      }
+ err:
+                       while ((skb = __skb_dequeue(&tmpq)))
+                               __skb_queue_tail(&errq, skb);
+@@ -1652,7 +1660,7 @@ static int setup_netfront(struct xenbus_
+                       struct netfront_queue *queue, unsigned int feature_split_evtchn)
+ {
+       struct xen_netif_tx_sring *txs;
+-      struct xen_netif_rx_sring *rxs;
++      struct xen_netif_rx_sring *rxs = NULL;
+       grant_ref_t gref;
+       int err;
+@@ -1672,21 +1680,21 @@ static int setup_netfront(struct xenbus_
+       err = xenbus_grant_ring(dev, txs, 1, &gref);
+       if (err < 0)
+-              goto grant_tx_ring_fail;
++              goto fail;
+       queue->tx_ring_ref = gref;
+       rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
+       if (!rxs) {
+               err = -ENOMEM;
+               xenbus_dev_fatal(dev, err, "allocating rx ring page");
+-              goto alloc_rx_ring_fail;
++              goto fail;
+       }
+       SHARED_RING_INIT(rxs);
+       FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
+       err = xenbus_grant_ring(dev, rxs, 1, &gref);
+       if (err < 0)
+-              goto grant_rx_ring_fail;
++              goto fail;
+       queue->rx_ring_ref = gref;
+       if (feature_split_evtchn)
+@@ -1699,22 +1707,28 @@ static int setup_netfront(struct xenbus_
+               err = setup_netfront_single(queue);
+       if (err)
+-              goto alloc_evtchn_fail;
++              goto fail;
+       return 0;
+       /* If we fail to setup netfront, it is safe to just revoke access to
+        * granted pages because backend is not accessing it at this point.
+        */
+-alloc_evtchn_fail:
+-      gnttab_end_foreign_access_ref(queue->rx_ring_ref, 0);
+-grant_rx_ring_fail:
+-      free_page((unsigned long)rxs);
+-alloc_rx_ring_fail:
+-      gnttab_end_foreign_access_ref(queue->tx_ring_ref, 0);
+-grant_tx_ring_fail:
+-      free_page((unsigned long)txs);
+-fail:
++ fail:
++      if (queue->rx_ring_ref != GRANT_INVALID_REF) {
++              gnttab_end_foreign_access(queue->rx_ring_ref, 0,
++                                        (unsigned long)rxs);
++              queue->rx_ring_ref = GRANT_INVALID_REF;
++      } else {
++              free_page((unsigned long)rxs);
++      }
++      if (queue->tx_ring_ref != GRANT_INVALID_REF) {
++              gnttab_end_foreign_access(queue->tx_ring_ref, 0,
++                                        (unsigned long)txs);
++              queue->tx_ring_ref = GRANT_INVALID_REF;
++      } else {
++              free_page((unsigned long)txs);
++      }
+       return err;
+ }
diff --git a/queue-4.14/xen-remove-gnttab_query_foreign_access.patch b/queue-4.14/xen-remove-gnttab_query_foreign_access.patch
new file mode 100644 (file)
index 0000000..220a448
--- /dev/null
@@ -0,0 +1,78 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:42 +0100
+Subject: xen: remove gnttab_query_foreign_access()
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 1dbd11ca75fe664d3e54607547771d021f531f59 upstream.
+
+Remove gnttab_query_foreign_access(), as it is unused and unsafe to
+use.
+
+All previous use cases assumed a grant would not be in use after
+gnttab_query_foreign_access() returned 0. This information is useless
+in best case, as it only refers to a situation in the past, which could
+have changed already.
+
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/grant-table.c |   19 -------------------
+ include/xen/grant_table.h |    2 --
+ 2 files changed, 21 deletions(-)
+
+--- a/drivers/xen/grant-table.c
++++ b/drivers/xen/grant-table.c
+@@ -114,13 +114,6 @@ struct gnttab_ops {
+        * return the frame.
+        */
+       unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref);
+-      /*
+-       * Query the status of a grant entry. Ref parameter is reference of
+-       * queried grant entry, return value is the status of queried entry.
+-       * Detailed status(writing/reading) can be gotten from the return value
+-       * by bit operations.
+-       */
+-      int (*query_foreign_access)(grant_ref_t ref);
+ };
+ struct unmap_refs_callback_data {
+@@ -255,17 +248,6 @@ int gnttab_grant_foreign_access(domid_t
+ }
+ EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
+-static int gnttab_query_foreign_access_v1(grant_ref_t ref)
+-{
+-      return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
+-}
+-
+-int gnttab_query_foreign_access(grant_ref_t ref)
+-{
+-      return gnttab_interface->query_foreign_access(ref);
+-}
+-EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
+-
+ static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
+ {
+       u16 flags, nflags;
+@@ -1029,7 +1011,6 @@ static const struct gnttab_ops gnttab_v1
+       .update_entry                   = gnttab_update_entry_v1,
+       .end_foreign_access_ref         = gnttab_end_foreign_access_ref_v1,
+       .end_foreign_transfer_ref       = gnttab_end_foreign_transfer_ref_v1,
+-      .query_foreign_access           = gnttab_query_foreign_access_v1,
+ };
+ static void gnttab_request_version(void)
+--- a/include/xen/grant_table.h
++++ b/include/xen/grant_table.h
+@@ -118,8 +118,6 @@ int gnttab_grant_foreign_transfer(domid_
+ unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
+ unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
+-int gnttab_query_foreign_access(grant_ref_t ref);
+-
+ /*
+  * operations on reserved batches of grant references
+  */
diff --git a/queue-4.14/xen-scsifront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch b/queue-4.14/xen-scsifront-don-t-use-gnttab_query_foreign_access-for-mapped-status.patch
new file mode 100644 (file)
index 0000000..0fa3769
--- /dev/null
@@ -0,0 +1,43 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:42 +0100
+Subject: xen/scsifront: don't use gnttab_query_foreign_access() for mapped status
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 33172ab50a53578a95691310f49567c9266968b0 upstream.
+
+It isn't enough to check whether a grant is still being in use by
+calling gnttab_query_foreign_access(), as a mapping could be realized
+by the other side just after having called that function.
+
+In case the call was done in preparation of revoking a grant it is
+better to do so via gnttab_try_end_foreign_access() and check the
+success of that operation instead.
+
+This is CVE-2022-23038 / part of XSA-396.
+
+Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/xen-scsifront.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/scsi/xen-scsifront.c
++++ b/drivers/scsi/xen-scsifront.c
+@@ -233,12 +233,11 @@ static void scsifront_gnttab_done(struct
+               return;
+       for (i = 0; i < shadow->nr_grants; i++) {
+-              if (unlikely(gnttab_query_foreign_access(shadow->gref[i]))) {
++              if (unlikely(!gnttab_try_end_foreign_access(shadow->gref[i]))) {
+                       shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME
+                                    "grant still in use by backend\n");
+                       BUG();
+               }
+-              gnttab_end_foreign_access(shadow->gref[i], 0, 0UL);
+       }
+       kfree(shadow->sg);
diff --git a/queue-4.14/xen-xenbus-don-t-let-xenbus_grant_ring-remove-grants-in-error-case.patch b/queue-4.14/xen-xenbus-don-t-let-xenbus_grant_ring-remove-grants-in-error-case.patch
new file mode 100644 (file)
index 0000000..336bdd6
--- /dev/null
@@ -0,0 +1,79 @@
+From foo@baz Thu Mar 10 02:39:42 PM CET 2022
+From: Juergen Gross <jgross@suse.com>
+Date: Fri, 25 Feb 2022 16:05:40 +0100
+Subject: xen/xenbus: don't let xenbus_grant_ring() remove grants in error case
+
+From: Juergen Gross <jgross@suse.com>
+
+Commit 3777ea7bac3113005b7180e6b9dadf16d19a5827 upstream.
+
+Letting xenbus_grant_ring() tear down grants in the error case is
+problematic, as the other side could already have used these grants.
+Calling gnttab_end_foreign_access_ref() without checking success is
+resulting in an unclear situation for any caller of xenbus_grant_ring()
+as in the error case the memory pages of the ring page might be
+partially mapped. Freeing them would risk unwanted foreign access to
+them, while not freeing them would leak memory.
+
+In order to remove the need to undo any gnttab_grant_foreign_access()
+calls, use gnttab_alloc_grant_references() to make sure no further
+error can occur in the loop granting access to the ring pages.
+
+It should be noted that this way of handling removes leaking of
+grant entries in the error case, too.
+
+This is CVE-2022-23040 / part of XSA-396.
+
+Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/xenbus/xenbus_client.c |   24 +++++++++++-------------
+ 1 file changed, 11 insertions(+), 13 deletions(-)
+
+--- a/drivers/xen/xenbus/xenbus_client.c
++++ b/drivers/xen/xenbus/xenbus_client.c
+@@ -368,7 +368,14 @@ int xenbus_grant_ring(struct xenbus_devi
+                     unsigned int nr_pages, grant_ref_t *grefs)
+ {
+       int err;
+-      int i, j;
++      unsigned int i;
++      grant_ref_t gref_head;
++
++      err = gnttab_alloc_grant_references(nr_pages, &gref_head);
++      if (err) {
++              xenbus_dev_fatal(dev, err, "granting access to ring page");
++              return err;
++      }
+       for (i = 0; i < nr_pages; i++) {
+               unsigned long gfn;
+@@ -378,23 +385,14 @@ int xenbus_grant_ring(struct xenbus_devi
+               else
+                       gfn = virt_to_gfn(vaddr);
+-              err = gnttab_grant_foreign_access(dev->otherend_id, gfn, 0);
+-              if (err < 0) {
+-                      xenbus_dev_fatal(dev, err,
+-                                       "granting access to ring page");
+-                      goto fail;
+-              }
+-              grefs[i] = err;
++              grefs[i] = gnttab_claim_grant_reference(&gref_head);
++              gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id,
++                                              gfn, 0);
+               vaddr = vaddr + XEN_PAGE_SIZE;
+       }
+       return 0;
+-
+-fail:
+-      for (j = 0; j < i; j++)
+-              gnttab_end_foreign_access_ref(grefs[j], 0);
+-      return err;
+ }
+ EXPORT_SYMBOL_GPL(xenbus_grant_ring);