Module Name: src Committed By: martin Date: Tue Feb 23 11:02:12 UTC 2021
Modified Files: src/sys/arch/xen/x86 [netbsd-9]: xen_shm_machdep.c Log Message: Pull up following revision(s) (requested by jdolecek in ticket #1210): sys/arch/xen/x86/xen_shm_machdep.c: revision 1.17 (via patch) in xen_shm_map(), make sure to unmap any successfully mapped pages before returning failure if there is partial failure fix detection of partial failure - GNTTABOP_map_grant_ref can actually re= turn zero for partial failure, so we need to always check all the entries to detect it previously, kernel triggered panic() for partial failure, leading to Dom0 page fault later; since the mapping failure can be triggered by malicious DomU via bad grant reference, it's important to expect the calls to fail, and handle it gracefully without crashing Dom0 part of fixes for XSA-362 To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.13.4.1 src/sys/arch/xen/x86/xen_shm_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/xen/x86/xen_shm_machdep.c diff -u src/sys/arch/xen/x86/xen_shm_machdep.c:1.13 src/sys/arch/xen/x86/xen_shm_machdep.c:1.13.4.1 --- src/sys/arch/xen/x86/xen_shm_machdep.c:1.13 Sun Jan 27 02:08:39 2019 +++ src/sys/arch/xen/x86/xen_shm_machdep.c Tue Feb 23 11:02:12 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: xen_shm_machdep.c,v 1.13 2019/01/27 02:08:39 pgoyette Exp $ */ +/* $NetBSD: xen_shm_machdep.c,v 1.13.4.1 2021/02/23 11:02:12 martin Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xen_shm_machdep.c,v 1.13 2019/01/27 02:08:39 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xen_shm_machdep.c,v 1.13.4.1 2021/02/23 11:02:12 martin Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -123,6 +123,7 @@ xen_shm_map(int nentries, int domid, gra vmem_addr_t new_va_pg; vaddr_t new_va; int ret, i, s; + int orig_nentries = nentries; #ifdef DIAGNOSTIC if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) { @@ -172,16 +173,71 @@ xen_shm_map(int nentries, int domid, gra } ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, op, nentries); - if (__predict_false(ret)) { - panic("xen_shm_map: HYPERVISOR_grant_table_op failed"); + if (__predict_false(ret < 0)) { +#ifdef DIAGNOSTIC + printf("%s: HYPERVISOR_grant_table_op failed %d\n", __func__, + ret); +#endif + goto bad; + } + + /* + * If ret is positive, it means there was an error in processing, + * and only first ret entries were actually handled. If it's zero, + * it only means all entries were processed, but there could still + * be failure. + */ + if (__predict_false(ret > 0 && ret < nentries)) { + nentries = ret; } for (i = 0; i < nentries; i++) { - if (__predict_false(op[i].status)) - return op[i].status; + if (__predict_false(op[i].status)) { +#ifdef DIAGNOSTIC + printf("%s: op[%d] bad status %d gref %u\n", __func__, + i, op[i].status, grefp[i]); +#endif + ret = 1; + continue; + } handlep[i] = op[i].handle; } + if (__predict_false(ret > 0)) { + int uncnt = 0; + gnttab_unmap_grant_ref_t unop[XENSHM_MAX_PAGES_PER_REQUEST]; + + /* + * When returning error, make sure the successfully mapped + * entries are unmapped before returning the error. + * xen_shm_unmap() can't be used, it assumes + * linear consecutive space. + */ + for (i = uncnt = 0; i < nentries; i++) { + if (op[i].status == 0) { + unop[uncnt].host_addr = new_va + i * PAGE_SIZE; + unop[uncnt].dev_bus_addr = 0; + unop[uncnt].handle = handlep[i]; + uncnt++; + } + } + if (uncnt > 0) { + ret = HYPERVISOR_grant_table_op( + GNTTABOP_unmap_grant_ref, unop, uncnt); + if (ret != 0) { + panic("%s: unmap on error recovery failed" + " %d", __func__, ret); + } + } +#ifdef DIAGNOSTIC + printf("%s: HYPERVISOR_grant_table_op bad entry\n", + __func__); +#endif +bad: + vmem_free(xen_shm_arena, new_va_pg, orig_nentries); + return EINVAL; + } + *vap = new_va; return 0; }