| From foo@baz Thu Mar 10 02:41:19 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 |
| @@ -377,11 +377,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); |