From: Paul Durrant <paul.durrant@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Stefano Stabellini <sstabellini@kernel.org>,
Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>,
Andrew Cooper <andrew.cooper3@citrix.com>,
Ian Jackson <ian.jackson@eu.citrix.com>, Tim Deegan <tim@xen.org>,
Paul Durrant <paul.durrant@citrix.com>,
Jan Beulich <jbeulich@suse.com>
Subject: [PATCH v9 06/11] x86/hvm/ioreq: add a new mappable resource type...
Date: Fri, 6 Oct 2017 13:25:14 +0100 [thread overview]
Message-ID: <20171006122519.30345-7-paul.durrant@citrix.com> (raw)
In-Reply-To: <20171006122519.30345-1-paul.durrant@citrix.com>
... XENMEM_resource_ioreq_server
This patch adds support for a new resource type that can be mapped using
the XENMEM_acquire_resource memory op.
If an emulator makes use of this resource type then, instead of mapping
gfns, the IOREQ server will allocate pages from the heap. These pages
will never be present in the P2M of the guest at any point and so are
not vulnerable to any direct attack by the guest. They are only ever
accessible by Xen and any domain that has mapping privilege over the
guest (which may or may not be limited to the domain running the emulator).
NOTE: Use of the new resource type is not compatible with use of
XEN_DMOP_get_ioreq_server_info unless the XEN_DMOP_no_gfns flag is
set.
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: George Dunlap <George.Dunlap@eu.citrix.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
---
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Tim Deegan <tim@xen.org>
v8:
- Re-base on new boilerplate.
- Adjust function signature of hvm_get_ioreq_server_frame(), and test
whether the bufioreq page is present.
v5:
- Use get_ioreq_server() function rather than indexing array directly.
- Add more explanation into comments to state than mapping guest frames
and allocation of pages for ioreq servers are not simultaneously
permitted.
- Add a comment into asm/ioreq.h stating the meaning of the index
value passed to hvm_get_ioreq_server_frame().
---
xen/arch/x86/hvm/ioreq.c | 140 ++++++++++++++++++++++++++++++++++++++++
xen/arch/x86/mm.c | 22 +++++++
xen/common/memory.c | 5 ++
xen/include/asm-x86/hvm/ioreq.h | 6 ++
xen/include/asm-x86/mm.h | 5 ++
xen/include/public/hvm/dm_op.h | 4 ++
xen/include/public/memory.h | 13 +++-
7 files changed, 194 insertions(+), 1 deletion(-)
diff --git a/xen/arch/x86/hvm/ioreq.c b/xen/arch/x86/hvm/ioreq.c
index bb4fadcc3d..7a95911b6b 100644
--- a/xen/arch/x86/hvm/ioreq.c
+++ b/xen/arch/x86/hvm/ioreq.c
@@ -266,6 +266,19 @@ static int hvm_map_ioreq_gfn(struct hvm_ioreq_server *s, bool buf)
struct hvm_ioreq_page *iorp = buf ? &s->bufioreq : &s->ioreq;
int rc;
+ if ( iorp->page )
+ {
+ /*
+ * If a page has already been allocated (which will happen on
+ * demand if hvm_get_ioreq_server_frame() is called), then
+ * mapping a guest frame is not permitted.
+ */
+ if ( gfn_eq(iorp->gfn, INVALID_GFN) )
+ return -EPERM;
+
+ return 0;
+ }
+
if ( d->is_dying )
return -EINVAL;
@@ -288,6 +301,61 @@ static int hvm_map_ioreq_gfn(struct hvm_ioreq_server *s, bool buf)
return rc;
}
+static int hvm_alloc_ioreq_mfn(struct hvm_ioreq_server *s, bool buf)
+{
+ struct domain *currd = current->domain;
+ struct hvm_ioreq_page *iorp = buf ? &s->bufioreq : &s->ioreq;
+
+ if ( iorp->page )
+ {
+ /*
+ * If a guest frame has already been mapped (which may happen
+ * on demand if hvm_get_ioreq_server_info() is called), then
+ * allocating a page is not permitted.
+ */
+ if ( !gfn_eq(iorp->gfn, INVALID_GFN) )
+ return -EPERM;
+
+ return 0;
+ }
+
+ /*
+ * Allocated IOREQ server pages are assigned to the emulating
+ * domain, not the target domain. This is because the emulator is
+ * likely to be destroyed after the target domain has been torn
+ * down, and we must use MEMF_no_refcount otherwise page allocation
+ * could fail if the emulating domain has already reached its
+ * maximum allocation.
+ */
+ iorp->page = alloc_domheap_page(currd, MEMF_no_refcount);
+ if ( !iorp->page )
+ return -ENOMEM;
+
+ iorp->va = __map_domain_page_global(iorp->page);
+ if ( !iorp->va )
+ {
+ iorp->page = NULL;
+ return -ENOMEM;
+ }
+
+ clear_page(iorp->va);
+ return 0;
+}
+
+static void hvm_free_ioreq_mfn(struct hvm_ioreq_server *s, bool buf)
+{
+ struct hvm_ioreq_page *iorp = buf ? &s->bufioreq : &s->ioreq;
+
+ if ( !iorp->page )
+ return;
+
+ unmap_domain_page_global(iorp->va);
+ iorp->va = NULL;
+
+ put_page(iorp->page);
+ iorp->page = NULL;
+}
+
bool is_ioreq_server_page(struct domain *d, const struct page_info *page)
{
const struct hvm_ioreq_server *s;
@@ -491,6 +559,27 @@ static void hvm_ioreq_server_unmap_pages(struct hvm_ioreq_server *s)
hvm_unmap_ioreq_gfn(s, false);
}
+static int hvm_ioreq_server_alloc_pages(struct hvm_ioreq_server *s)
+{
+ int rc;
+
+ rc = hvm_alloc_ioreq_mfn(s, false);
+
+ if ( !rc && (s->bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF) )
+ rc = hvm_alloc_ioreq_mfn(s, true);
+
+ if ( rc )
+ hvm_free_ioreq_mfn(s, false);
+
+ return rc;
+}
+
+static void hvm_ioreq_server_free_pages(struct hvm_ioreq_server *s)
+{
+ hvm_free_ioreq_mfn(s, true);
+ hvm_free_ioreq_mfn(s, false);
+}
+
static void hvm_ioreq_server_free_rangesets(struct hvm_ioreq_server *s)
{
unsigned int i;
@@ -619,7 +708,18 @@ static int hvm_ioreq_server_init(struct hvm_ioreq_server *s,
fail_add:
hvm_ioreq_server_remove_all_vcpus(s);
+
+ /*
+ * NOTE: It is safe to call both hvm_ioreq_server_unmap_pages() and
+ * hvm_ioreq_server_free_pages() in that order.
+ * This is because the former will do nothing if the pages
+ * are not mapped, leaving the page to be freed by the latter.
+ * However if the pages are mapped then the former will set
+ * the page_info pointer to NULL, meaning the latter will do
+ * nothing.
+ */
hvm_ioreq_server_unmap_pages(s);
+ hvm_ioreq_server_free_pages(s);
return rc;
}
@@ -629,6 +729,7 @@ static void hvm_ioreq_server_deinit(struct hvm_ioreq_server *s)
ASSERT(!s->enabled);
hvm_ioreq_server_remove_all_vcpus(s);
hvm_ioreq_server_unmap_pages(s);
+ hvm_ioreq_server_free_pages(s);
hvm_ioreq_server_free_rangesets(s);
}
@@ -784,6 +885,45 @@ int hvm_get_ioreq_server_info(struct domain *d, ioservid_t id,
return rc;
}
+int hvm_get_ioreq_server_frame(struct domain *d, ioservid_t id,
+ unsigned int idx, mfn_t *mfn)
+{
+ struct hvm_ioreq_server *s;
+ int rc;
+
+ spin_lock_recursive(&d->arch.hvm_domain.ioreq_server.lock);
+
+ if ( id == DEFAULT_IOSERVID )
+ return -EOPNOTSUPP;
+
+ s = get_ioreq_server(d, id);
+
+ ASSERT(!IS_DEFAULT(s));
+
+ rc = hvm_ioreq_server_alloc_pages(s);
+ if ( rc )
+ goto out;
+
+ if ( idx == 0 )
+ {
+ rc = -ENOENT;
+ if ( !HANDLE_BUFIOREQ(s) )
+ goto out;
+
+ *mfn = _mfn(page_to_mfn(s->bufioreq.page));
+ rc = 0;
+ }
+ else if ( idx == 1 )
+ *mfn = _mfn(page_to_mfn(s->ioreq.page));
+ else
+ rc = -EINVAL;
+
+ out:
+ spin_unlock_recursive(&d->arch.hvm_domain.ioreq_server.lock);
+
+ return rc;
+}
+
int hvm_map_io_range_to_ioreq_server(struct domain *d, ioservid_t id,
uint32_t type, uint64_t start,
uint64_t end)
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index d9df5ca69f..c9bc4a4e92 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -122,6 +122,7 @@
#include <asm/fixmap.h>
#include <asm/io_apic.h>
#include <asm/pci.h>
+#include <asm/hvm/ioreq.h>
#include <asm/hvm/grant_table.h>
#include <asm/pv/grant_table.h>
@@ -3866,6 +3867,27 @@ int xenmem_add_to_physmap_one(
return rc;
}
+int xenmem_acquire_ioreq_server(struct domain *d, unsigned int id,
+ unsigned long frame,
+ unsigned long nr_frames,
+ unsigned long mfn_list[])
+{
+ unsigned int i;
+
+ for ( i = 0; i < nr_frames; i++ )
+ {
+ mfn_t mfn;
+ int rc = hvm_get_ioreq_server_frame(d, id, frame + i, &mfn);
+
+ if ( rc )
+ return rc;
+
+ mfn_list[i] = mfn_x(mfn);
+ }
+
+ return 0;
+}
+
long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
{
int rc;
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 910c0c5063..80a3f42875 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -988,6 +988,11 @@ static int acquire_resource(const xen_mem_acquire_resource_t *xmar)
switch ( xmar->type )
{
+ case XENMEM_resource_ioreq_server:
+ rc = xenmem_acquire_ioreq_server(d, xmar->id, xmar->frame,
+ xmar->nr_frames, mfn_list);
+ break;
+
default:
rc = -EOPNOTSUPP;
break;
diff --git a/xen/include/asm-x86/hvm/ioreq.h b/xen/include/asm-x86/hvm/ioreq.h
index 1829fcf43e..a4f58dc9ee 100644
--- a/xen/include/asm-x86/hvm/ioreq.h
+++ b/xen/include/asm-x86/hvm/ioreq.h
@@ -31,6 +31,12 @@ int hvm_get_ioreq_server_info(struct domain *d, ioservid_t id,
unsigned long *ioreq_gfn,
unsigned long *bufioreq_gfn,
evtchn_port_t *bufioreq_port);
+/*
+ * Get the mfn of either the buffered or synchronous ioreq frame.
+ * (idx == 0 -> buffered, idx == 1 -> synchronous).
+ */
+int hvm_get_ioreq_server_frame(struct domain *d, ioservid_t id,
+ unsigned int idx, mfn_t *mfn);
int hvm_map_io_range_to_ioreq_server(struct domain *d, ioservid_t id,
uint32_t type, uint64_t start,
uint64_t end);
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index f2e0f498c4..637b1eee1c 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -615,4 +615,9 @@ static inline bool arch_mfn_in_directmap(unsigned long mfn)
return mfn <= (virt_to_mfn(eva - 1) + 1);
}
+int xenmem_acquire_ioreq_server(struct domain *d, unsigned int id,
+ unsigned long frame,
+ unsigned long nr_frames,
+ unsigned long mfn_list[]);
+
#endif /* __ASM_X86_MM_H__ */
diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h
index 9677bd74e7..59b6006910 100644
--- a/xen/include/public/hvm/dm_op.h
+++ b/xen/include/public/hvm/dm_op.h
@@ -90,6 +90,10 @@ struct xen_dm_op_create_ioreq_server {
* the frame numbers passed back in gfns <ioreq_gfn> and <bufioreq_gfn>
* respectively. (If the IOREQ Server is not handling buffered emulation
* only <ioreq_gfn> will be valid).
+ *
+ * NOTE: To access the synchronous ioreq structures and buffered ioreq
+ * ring, it is preferable to use the XENMEM_acquire_resource memory
+ * op specifying resource type XENMEM_resource_ioreq_server.
*/
#define XEN_DMOP_get_ioreq_server_info 2
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index 3aa8fb2fe1..e30a4d9794 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -609,15 +609,26 @@ struct xen_mem_acquire_resource {
domid_t domid;
/* IN - the type of resource */
uint16_t type;
+
+#define XENMEM_resource_ioreq_server 0
+
/*
* IN - a type-specific resource identifier, which must be zero
* unless stated otherwise.
+ *
+ * type == XENMEM_resource_ioreq_server -> id == ioreq server id
*/
uint32_t id;
/* IN - number of (4K) frames of the resource to be mapped */
uint32_t nr_frames;
uint32_t pad;
- /* IN - the index of the initial frame to be mapped */
+ /* IN - the index of the initial frame to be mapped
+ *
+ * type == XENMEM_resource_ioreq_server -> frame == 0 -> bufioreq
+ * page
+ * frame == 1 -> ioreq
+ * page
+ */
uint64_aligned_t frame;
/* IN/OUT - If the tools domain is PV then, upon return, gmfn_list
* will be populated with the MFNs of the resource.
--
2.11.0
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
next prev parent reply other threads:[~2017-10-06 12:25 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-06 12:25 [PATCH v9 00/11] x86: guest resource mapping Paul Durrant
2017-10-06 12:25 ` [PATCH v9 01/11] x86/hvm/ioreq: maintain an array of ioreq servers rather than a list Paul Durrant
2017-10-09 12:40 ` Jan Beulich
2017-10-09 12:45 ` Paul Durrant
2017-10-06 12:25 ` [PATCH v9 02/11] x86/hvm/ioreq: simplify code and use consistent naming Paul Durrant
2017-10-06 12:25 ` [PATCH v9 03/11] x86/hvm/ioreq: use gfn_t in struct hvm_ioreq_page Paul Durrant
2017-10-06 12:25 ` [PATCH v9 04/11] x86/hvm/ioreq: defer mapping gfns until they are actually requsted Paul Durrant
2017-10-09 12:45 ` Jan Beulich
2017-10-09 12:47 ` Paul Durrant
2017-10-06 12:25 ` [PATCH v9 05/11] x86/mm: add HYPERVISOR_memory_op to acquire guest resources Paul Durrant
2017-10-09 13:05 ` Jan Beulich
2017-10-10 13:26 ` Paul Durrant
2017-10-11 8:20 ` Jan Beulich
2017-10-09 14:23 ` Jan Beulich
2017-10-10 14:10 ` Paul Durrant
2017-10-10 14:37 ` Paul Durrant
2017-10-11 8:30 ` Jan Beulich
2017-10-11 8:38 ` Paul Durrant
2017-10-11 8:48 ` Jan Beulich
2017-10-06 12:25 ` Paul Durrant [this message]
2017-10-09 15:20 ` [PATCH v9 06/11] x86/hvm/ioreq: add a new mappable resource type Jan Beulich
2017-10-10 14:45 ` Paul Durrant
2017-10-11 8:35 ` Jan Beulich
2017-10-06 12:25 ` [PATCH v9 07/11] x86/mm: add an extra command to HYPERVISOR_mmu_update Paul Durrant
2017-10-09 15:44 ` Jan Beulich
2017-10-06 12:25 ` [PATCH v9 08/11] tools/libxenforeignmemory: add support for resource mapping Paul Durrant
2017-10-06 12:25 ` [PATCH v9 09/11] tools/libxenforeignmemory: reduce xenforeignmemory_restrict code footprint Paul Durrant
2017-10-06 12:25 ` [PATCH v9 10/11] common: add a new mappable resource type: XENMEM_resource_grant_table Paul Durrant
2017-10-10 10:25 ` Jan Beulich
2017-10-10 16:01 ` Paul Durrant
2017-10-11 8:47 ` Jan Beulich
2017-10-11 8:54 ` Paul Durrant
2017-10-11 9:43 ` Jan Beulich
2017-10-11 9:54 ` Paul Durrant
2017-10-11 10:12 ` Jan Beulich
2017-10-06 12:25 ` [PATCH v9 11/11] tools/libxenctrl: use new xenforeignmemory API to seed grant table Paul Durrant
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171006122519.30345-7-paul.durrant@citrix.com \
--to=paul.durrant@citrix.com \
--cc=andrew.cooper3@citrix.com \
--cc=ian.jackson@eu.citrix.com \
--cc=jbeulich@suse.com \
--cc=konrad.wilk@oracle.com \
--cc=sstabellini@kernel.org \
--cc=tim@xen.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).