Skip to contentSkip to conversation

Allow setting up shared memory areas between VMs from xl config files

PATCH Superseded Zhongze Liu 4 participants 29 messages Oct 19, 2017 – Nov 9, 2017

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v3 cover Allow setting up shared memory areas between VMs from xl config files

This series implements the new xl config entry proposed in [1]. Users can use the new config entry to statically setup shared memory areas among VMs that don't have grant table support so that they could communicate with each other through the static shared memory areas.

[1] Proposla to allow setting up shared memory areas between VMs from xl config file:
https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

v3:
* Added the docs
* Changed the order of patches to reflect their internal dependencies
* Fixed the error handling when memory mapping are done but the xs trasaction fails
* Changed the xsm hooks to lookup the current domain themselves instead of getting it as a parameter

Cheers,

Zhongze Liu (7):
libxc: add xc_domain_remove_from_physmap to wrap
XENMEM_remove_from_physmap
xsm: flask: change the dummy xsm policy and flask hook for
map_gmfn_foregin
libxl: introduce a new structure to represent static shared memory
regions
libxl: support mapping static shared memory areas during domain
creation
libxl: support unmapping static shared memory areas during domain
destruction
libxl:xl: add parsing code to parse "libxl_static_sshm" from xl config
files
docs: documentation about static shared memory regions

 docs/man/xl-static-shm-configuration.pod.5 | 257 +++++++++++++++
 docs/man/xl.cfg.pod.5.in                   |   8 +
 docs/misc/xenstore-paths.markdown          |  47 +++
 tools/flask/policy/modules/xen.if          |   2 +
 tools/libxc/include/xenctrl.h              |   4 +
 tools/libxc/xc_domain.c                    |  11 +
 tools/libxl/Makefile                       |   4 +-
 tools/libxl/libxl.h                        |   4 +
 tools/libxl/libxl_arch.h                   |   6 +
 tools/libxl/libxl_arm.c                    |  15 +
 tools/libxl/libxl_create.c                 |  27 ++
 tools/libxl/libxl_domain.c                 |   5 +
 tools/libxl/libxl_internal.h               |  15 +
 tools/libxl/libxl_sshm.c                   | 500 +++++++++++++++++++++++++++++
 tools/libxl/libxl_types.idl                |  32 +-
 tools/libxl/libxl_x86.c                    |  18 ++
 tools/libxl/libxlu_sshm.c                  | 210 ++++++++++++
 tools/libxl/libxlutil.h                    |   6 +
 tools/xl/xl_parse.c                        |  24 +-
 xen/include/xsm/dummy.h                    |   3 +-
 xen/xsm/flask/hooks.c                      |   4 +-
 xen/xsm/flask/policy/access_vectors        |   4 +
 22 files changed, 1199 insertions(+), 7 deletions(-)
 create mode 100644 docs/man/xl-static-shm-configuration.pod.5
 create mode 100644 tools/libxl/libxl_sshm.c
 create mode 100644 tools/libxl/libxlu_sshm.c
Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
#1 lore raw

PATCH v3 1/7 libxc: add xc_domain_remove_from_physmap to wrap XENMEM_remove_from_physmap

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file". See:

https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Then plan is to use XENMEM_add_to_physmap_batch to map the shared pages from one domU to another and use XENMEM_remove_from_physmap to cancel the sharing. A wrapper to XENMEM_add_to_physmap_batch was added in the following commit:

commit 20e725e9364cff4a29945f66986ecd88cca8743d

Now add the wrapper to XENMEM_remove_from_physmap.

Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>
---
 tools/libxc/include/xenctrl.h |  4 ++++
 tools/libxc/xc_domain.c       | 11 +++++++++++
 2 files changed, 15 insertions(+)
tools/libxc/include/xenctrl.h +4 -0
index 666db0b919..0d8364ea4b 100644
@@ -1415,6 +1415,10 @@ int xc_domain_add_to_physmap_batch(xc_interface *xch,
                                    xen_pfn_t *gfpns,
                                    int *errs);
 
+int xc_domain_remove_from_physmap(xc_interface *xch,
+                                  domid_t domid,
+                                  xen_pfn_t gpfn);
+
 int xc_domain_populate_physmap(xc_interface *xch,
                                uint32_t domid,
                                unsigned long nr_extents,
tools/libxc/xc_domain.c +11 -0
index 3ccd27f101..b8a9ff87e9 100644
@@ -1104,6 +1104,17 @@ out:
     return rc;
 }
 
+int xc_domain_remove_from_physmap(xc_interface *xch,
+                                  domid_t domid,
+                                  xen_pfn_t gpfn)
+{
+    struct xen_remove_from_physmap xrfp = {
+        .domid = domid,
+        .gpfn = gpfn,
+    };
+    return do_memory_op(xch, XENMEM_remove_from_physmap, &xrfp, sizeof(xrfp));
+}
+
 int xc_domain_claim_pages(xc_interface *xch,
                                uint32_t domid,
                                unsigned long nr_pages)
Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
#2 lore raw

Re: [PATCH v3 1/7] libxc: add xc_domain_remove_from_physmap to wrap XENMEM_remove_from_physmap

Quoted 32 lines · Zhongze Liu

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file". See:

https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Then plan is to use XENMEM_add_to_physmap_batch to map the shared pages from one domU to another and use XENMEM_remove_from_physmap to cancel the sharing. A wrapper to XENMEM_add_to_physmap_batch was added in the following commit:

commit 20e725e9364cff4a29945f66986ecd88cca8743d

Now add the wrapper to XENMEM_remove_from_physmap.

Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>
---
 tools/libxc/include/xenctrl.h |  4 ++++
 tools/libxc/xc_domain.c       | 11 +++++++++++
 2 files changed, 15 insertions(+)
tools/libxc/include/xenctrl.h +0 -0
index 666db0b919..0d8364ea4b 100644

tools/libxc/include/xenctrl.h int xc_domain_add_to_physmap_batch(xc_interface *xch, · line 1419

Quoted 5 lines
tools/libxc/include/xenctrl.h +2 -0
@@ -1415,6 +1415,10 @@ int xc_domain_add_to_physmap_batch(xc_interface *xch,
                                    xen_pfn_t *gfpns,
                                    int *errs);
 
+int xc_domain_remove_from_physmap(xc_interface *xch,
+                                  domid_t domid,

We recently made changes to use uint32_t for domid.

You can keep my ack after the change.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#3 lore raw

PATCH v3 2/7 xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

In reply to Zhongze Liu

The original dummy xsm_map_gmfn_foregin checks if source domain has the proper privileges over the target domain. Under this policy, it's not allowed if a Dom0 wants to map pages from one DomU to another, which restricts some useful yet not dangerous use cases of the API, such as sharing pages among DomU's by calling XENMEM_add_to_physmap from Dom0.

For the dummy xsm_map_gmfn_foregin, change to policy to: IFF the current domain has the proper privileges on (d) and (t), grant the access.

For the flask side: 1) Introduce a new av permission MMU__SHARE_MEM to denote if two domains can share memory through map_gmfn_foregin. 2) Change to hook to grant the access IFF the current domain has proper MMU privileges on (d) and (t), and MMU__SHARE_MEM is allowed between (d) and (t). 3) Modify the default xen.te to allow MMU__SHARE_MEM for normal domains that allow grant mapping/event channels.

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Daniel De Graaf <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* Change several if statements to the GCC '... = a ?: b' extention.
* lookup the current domain in the hooks instead of passing it as an arg

---
 tools/flask/policy/modules/xen.if   | 2 ++
 xen/include/xsm/dummy.h             | 3 ++-
 xen/xsm/flask/hooks.c               | 4 +++-
 xen/xsm/flask/policy/access_vectors | 4 ++++
 4 files changed, 11 insertions(+), 2 deletions(-)
tools/flask/policy/modules/xen.if +2 -0
index 55437496f6..3ffd1c6239 100644
@@ -127,6 +127,8 @@ define(`domain_comms', `
 	domain_event_comms($1, $2)
 	allow $1 $2:grant { map_read map_write copy unmap };
 	allow $2 $1:grant { map_read map_write copy unmap };
+	allow $1 $2:mmu share_mem;
+	allow $2 $1:mmu share_mem;
 ')
 
 # domain_self_comms(domain)
xen/include/xsm/dummy.h +2 -1
index b2cd56cdc5..65e7060ad5 100644
@@ -516,7 +516,8 @@ static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,
 static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain *d, struct domain *t)
 {
     XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
 }
 
 static XSM_INLINE int xsm_hvm_param(XSM_DEFAULT_ARG struct domain *d, unsigned long op)
xen/xsm/flask/hooks.c +3 -1
index f01b4cfaaa..16103bafc9 100644
@@ -1199,7 +1199,9 @@ static int flask_remove_from_physmap(struct domain *d1, struct domain *d2)
 
 static int flask_map_gmfn_foreign(struct domain *d, struct domain *t)
 {
-    return domain_has_perm(d, t, SECCLASS_MMU, MMU__MAP_READ | MMU__MAP_WRITE);
+    return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__MAP_READ | MMU__MAP_WRITE) ?:
+        domain_has_perm(current->domain, t, SECCLASS_MMU, MMU__MAP_READ | MMU__MAP_WRITE) ?:
+        domain_has_perm(d, t, SECCLASS_MMU, MMU__SHARE_MEM);
 }
 
 static int flask_hvm_param(struct domain *d, unsigned long op)
xen/xsm/flask/policy/access_vectors +4 -0
index 3a2d863b8f..a0330f914a 100644
@@ -387,6 +387,10 @@ class mmu
 # Allow a privileged domain to install a map of a page it does not own.  Used
 # for stub domain device models with the PV framebuffer.
     target_hack
+# Checked when using map_gmfn_foreign to share memory:
+#  source = domain whose memory is being shared
+#  target = client domain
+    share_mem
 }
 
 # control of the paging_domctl split by subop
Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
#4 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

xen/include/xsm/dummy.h static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1, · line 521

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 19.10.17 at 04:36, <[email protected]> wrote:
xen/include/xsm/dummy.h +2 -1
@@ -516,7 +516,8 @@ static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,
 static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain *d, struct domain *t)
 {
     XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
 }

When all three domains are different, how does the changed policy reflect the original "d has privilege over t" requirement? I understand you want to relax the current condition, but this shouldn't come at the price of granting access when access should be denied. Nor the inverse - the current domain not having privilege over both does also not mean d doesn't have the necessary privilege over t.

I continue to think that you can't validly retrofit the new intended functionality onto the existing hypercall, even if nothing except the permission check needs to be different.

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#5 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Quoted 20 lines · Jan Beulich

xen/include/xsm/dummy.h static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1, · line 521

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 19.10.17 at 04:36, <[email protected]> wrote:
xen/include/xsm/dummy.h +2 -1
@@ -516,7 +516,8 @@ static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,
  static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain *d, struct domain *t)
  {
      XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
  }

When all three domains are different, how does the changed policy reflect the original "d has privilege over t" requirement? I understand you want to relax the current condition, but this shouldn't come at the price of granting access when access should be denied. Nor the inverse - the current domain not having privilege over both does also not mean d doesn't have the necessary privilege over t.

Quoted 5 lines

I continue to think that you can't validly retrofit the new intended functionality onto the existing hypercall, even if nothing except the permission check needs to be different.

Jan

If this operation is going to be allowed at all (and I agree it has valid use cases), then there won't be a privilege relationship between
(d) and (t) to check - they'll both be (somewhat related) domUs as far as Xen can tell. If this hypercall isn't used, adding a new hypercall (subop) is the only way I'd see to do it - and that seems very redundant as it'd need to do all the same checks except for the one about the relationship between (d) and (t). I don't see the reason why the existing hypercall should deny being used for that purpose once it's possible using other means.

The only possible problem that springs to mind is a restricted kernel interface (such as the one used by QEMU in dom0 that restricts to a single target domain) that now doesn't realize it's relaying an operation that also requires permission over (t) after only checking that the origin is allowed to modify (d).

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#6 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Quoted 30 lines
Quoted 1 line
Quoted 1 line · On 19.10.17 at 19:36, <[email protected]> wrote:
Quoted 4 lines · Jan Beulich

xen/include/xsm/dummy.h static XSM_INLINE int

Quoted 4 lines
Quoted 1 line
Quoted 1 line · On 19.10.17 at 04:36, <[email protected]> wrote:
xen/include/xsm/dummy.h +0 -0
@@ -516,7 +516,8 @@ static XSM_INLINE int 

xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,

Quoted 1 line

xen/include/xsm/dummy.h static XSM_INLINE int · line 516

Quoted 1 line
xen/include/xsm/dummy.h +0 -0
  static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain 

*d, struct domain *t)

Quoted 15 lines

xen/include/xsm/dummy.h static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1, · line 521

Quoted 6 lines
xen/include/xsm/dummy.h +2 -1
  {
      XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
  }

When all three domains are different, how does the changed policy reflect the original "d has privilege over t" requirement? I understand you want to relax the current condition, but this shouldn't come at the price of granting access when access should be denied. Nor the inverse - the current domain not having privilege over both does also not mean d doesn't have the necessary privilege over t.

Quoted 5 lines

I continue to think that you can't validly retrofit the new intended functionality onto the existing hypercall, even if nothing except the permission check needs to be different.

Jan

Quoted 9 lines

If this operation is going to be allowed at all (and I agree it has valid use cases), then there won't be a privilege relationship between
(d) and (t) to check - they'll both be (somewhat related) domUs as far as Xen can tell. If this hypercall isn't used, adding a new hypercall (subop) is the only way I'd see to do it - and that seems very redundant as it'd need to do all the same checks except for the one about the relationship between (d) and (t). I don't see the reason why the existing hypercall should deny being used for that purpose once it's possible using other means.

One problem is, as you mention here, ...

Quoted 5 lines

The only possible problem that springs to mind is a restricted kernel interface (such as the one used by QEMU in dom0 that restricts to a single target domain) that now doesn't realize it's relaying an operation that also requires permission over (t) after only checking that the origin is allowed to modify (d).

... the delegation of privilege checking responsibility to a possibly untrusted environment. Plus, as explained before, current callers expect privilege of d over t to be validated, which isn't happening anymore with the proposed change. If the existing sub-op was to be modified, I think we'd need (with c representing the current domain)
- (d over t) || ((c over d) && (c over t)) for not regressing the pre-existing use case,
- only (c over d) && (c over t) for not permitting something that isn't intended to be permitted in the new use case.
Unless the sub-op has room for adding a flag to indicate which of the two is meant (I didn't check), I don't see a way around adding another sub-op, no matter how similar this would end up being.

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#7 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Quoted 63 lines · Jan Beulich
Quoted 30 lines
Quoted 1 line
Quoted 1 line · On 19.10.17 at 19:36, <[email protected]> wrote:
Quoted 4 lines · Jan Beulich

xen/include/xsm/dummy.h static XSM_INLINE int

Quoted 4 lines
Quoted 1 line
Quoted 1 line · On 19.10.17 at 04:36, <[email protected]> wrote:
xen/include/xsm/dummy.h +0 -0
@@ -516,7 +516,8 @@ static XSM_INLINE int

xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,

Quoted 1 line

xen/include/xsm/dummy.h static XSM_INLINE int · line 516

Quoted 1 line
xen/include/xsm/dummy.h +0 -0
   static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain

*d, struct domain *t)

Quoted 15 lines

xen/include/xsm/dummy.h static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1, · line 521

Quoted 6 lines
xen/include/xsm/dummy.h +2 -1
   {
       XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
   }

When all three domains are different, how does the changed policy reflect the original "d has privilege over t" requirement? I understand you want to relax the current condition, but this shouldn't come at the price of granting access when access should be denied. Nor the inverse - the current domain not having privilege over both does also not mean d doesn't have the necessary privilege over t.

Quoted 5 lines

I continue to think that you can't validly retrofit the new intended functionality onto the existing hypercall, even if nothing except the permission check needs to be different.

Jan

Quoted 9 lines

If this operation is going to be allowed at all (and I agree it has valid use cases), then there won't be a privilege relationship between
(d) and (t) to check - they'll both be (somewhat related) domUs as far as Xen can tell. If this hypercall isn't used, adding a new hypercall (subop) is the only way I'd see to do it - and that seems very redundant as it'd need to do all the same checks except for the one about the relationship between (d) and (t). I don't see the reason why the existing hypercall should deny being used for that purpose once it's possible using other means.

One problem is, as you mention here, ...

Quoted 5 lines

The only possible problem that springs to mind is a restricted kernel interface (such as the one used by QEMU in dom0 that restricts to a single target domain) that now doesn't realize it's relaying an operation that also requires permission over (t) after only checking that the origin is allowed to modify (d).

... the delegation of privilege checking responsibility to a possibly untrusted environment. Plus, as explained before, current callers expect privilege of d over t to be validated, which isn't happening anymore with the proposed change. If the existing sub-op was to be modified, I think we'd need (with c representing the current domain)
- (d over t) || ((c over d) && (c over t)) for not regressing the pre-existing use case,
- only (c over d) && (c over t) for not permitting something that isn't intended to be permitted in the new use case.
Unless the sub-op has room for adding a flag to indicate which of the two is meant (I didn't check), I don't see a way around adding another sub-op, no matter how similar this would end up being.

Quoted 1 line

Jan

I would say the current lack of a check for (c over t) is an oversight, which mostly doesn't matter because the ability to modify arbitrary memory in your target is transitive in almost any security model (c can modify d's code to modify t, so a malicious c can compromise t anyway). If the three domains are all different, the only way this can happen in non-XSM is for (c) to be dom0 or for your device model to have a device model (which I don't think is forbidden, but doubt anyone uses).

I now agree that this deserves a new subop, since this code is reached via the stable memory_op and not just a domctl.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#8 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Hi Daniel and Jan,

2017-10-20 21:34 GMT+08:00 Daniel De Graaf <[email protected]>:

Quoted 88 lines · Jan Beulich
Quoted 76 lines
Quoted 41 lines
Quoted 2 lines
Quoted 2 lines · On 19.10.17 at 19:36, <[email protected]> wrote:
Quoted 6 lines · Jan Beulich

xen/include/xsm/dummy.h static XSM_INLINE int

Quoted 6 lines
Quoted 2 lines
Quoted 2 lines · On 19.10.17 at 04:36, <[email protected]> wrote:
xen/include/xsm/dummy.h +0 -0
@@ -516,7 +516,8 @@ static XSM_INLINE int

xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,

Quoted 3 lines
Quoted 3 lines
xen/include/xsm/dummy.h +0 -0
   static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct

domain

*d, struct domain *t)

Quoted 17 lines

xen/include/xsm/dummy.h static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1, · line 521

Quoted 7 lines
   {
       XSM_ASSERT_ACTION(XSM_TARGET);
xen/include/xsm/dummy.h +2 -1
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
   }

When all three domains are different, how does the changed policy reflect the original "d has privilege over t" requirement? I understand you want to relax the current condition, but this shouldn't come at the price of granting access when access should be denied. Nor the inverse - the current domain not having privilege over both does also not mean d doesn't have the necessary privilege over t.

Quoted 5 lines

I continue to think that you can't validly retrofit the new intended functionality onto the existing hypercall, even if nothing except the permission check needs to be different.

Jan

Quoted 9 lines

If this operation is going to be allowed at all (and I agree it has valid use cases), then there won't be a privilege relationship between
(d) and (t) to check - they'll both be (somewhat related) domUs as far as Xen can tell. If this hypercall isn't used, adding a new hypercall (subop) is the only way I'd see to do it - and that seems very redundant as it'd need to do all the same checks except for the one about the relationship between (d) and (t). I don't see the reason why the existing hypercall should deny being used for that purpose once it's possible using other means.

One problem is, as you mention here, ...

Quoted 5 lines

The only possible problem that springs to mind is a restricted kernel interface (such as the one used by QEMU in dom0 that restricts to a single target domain) that now doesn't realize it's relaying an operation that also requires permission over (t) after only checking that the origin is allowed to modify (d).

... the delegation of privilege checking responsibility to a possibly untrusted environment. Plus, as explained before, current callers expect privilege of d over t to be validated, which isn't happening anymore with the proposed change. If the existing sub-op was to be modified, I think we'd need (with c representing the current domain)
- (d over t) || ((c over d) && (c over t)) for not regressing the pre-existing use case,
- only (c over d) && (c over t) for not permitting something that isn't intended to be permitted in the new use case.
Unless the sub-op has room for adding a flag to indicate which of the two is meant (I didn't check), I don't see a way around adding another sub-op, no matter how similar this would end up being.

Quoted 1 line

Jan

I would say the current lack of a check for (c over t) is an oversight, which mostly doesn't matter because the ability to modify arbitrary memory in your target is transitive in almost any security model (c can modify d's code to modify t, so a malicious c can compromise t anyway). If the three domains are all different, the only way this can happen in non-XSM is for (c) to be dom0 or for your device model to have a device model (which I don't think is forbidden, but doubt anyone uses).

Quoted 2 lines

I now agree that this deserves a new subop, since this code is reached via the stable memory_op and not just a domctl.

How about changing the policy to (c over d) && ((d over t) || (c over t))? Given that (c over d) is a must, which is always checked somewhere higher in the call stack as Daniel pointed out, permitting (d over t) or (c over t) actually infers
permitting the other.

- if you permit (d over t) but not (c over t):
Given (c over t),
(c) can first map the src page from (t) into its own memory space and then map this page from its own memory space to (d)'s memory space.

- if you permit (c over t) but not (d over t):
Given (d over t),
(c) can first map (d)'s pages into its own memory space and modify (d)'s code to issues a hypercall that maps (t)'s memory pages into (d)'s memory space.

I'm not very familiar with Xen's security model. So I might be totally wrong here.
If so, please correct me.

And if you still think adding a new subop is necessary, do you have any suggestions
on this?

Cheers,

Zhongze Liu

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#9 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 22.10.17 at 13:21, <[email protected]> wrote:

How about changing the policy to (c over d) && ((d over t) || (c over t))? Given that (c over d) is a must, which is always checked somewhere higher in the call stack as Daniel pointed out, permitting (d over t) or (c over t) actually infers
permitting the other.

- if you permit (d over t) but not (c over t):
Given (c over t),
(c) can first map the src page from (t) into its own memory space and then map this page from its own memory space to (d)'s memory space.

Would that work? The page, when in (c)'s space, is still owned by (t), so I don't see how mapping into (d)'s space could become possible just because it's mapped into (c)'s.

Quoted 4 lines

- if you permit (c over t) but not (d over t):
Given (d over t),
(c) can first map (d)'s pages into its own memory space and modify (d)'s code to issues a hypercall that maps (t)'s memory pages into (d)'s memory space.

I can buy this one (after having thought about it a little only for now), albeit (c) modifying code in (d) is certainly something I'd call abuse rather than use of permissions.

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#10 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Hi Jan,

2017-10-23 15:26 GMT+08:00 Jan Beulich <[email protected]>:

Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line · On 22.10.17 at 13:21, <[email protected]> wrote:

How about changing the policy to (c over d) && ((d over t) || (c over t))? Given that (c over d) is a must, which is always checked somewhere higher in the call stack as Daniel pointed out, permitting (d over t) or (c over t) actually infers
permitting the other.

Quoted 8 lines
Quoted 4 lines

- if you permit (d over t) but not (c over t):
Given (c over t),
(c) can first map the src page from (t) into its own memory space and then map this page from its own memory space to (d)'s memory space.

Would that work? The page, when in (c)'s space, is still owned by (t), so I don't see how mapping into (d)'s space could become possible just because it's mapped into (c)'s.

Yes, indeed. This won't work. Sorry for giving a wrong example here.

I think I now agree to add a new subop, too.

Cheers,

Zhongze Liu

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#11 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Hi,

My current plan is to add the following new MAPSPACE to public/memory.h:

+#define XENMEMSPACE_gmfn_foreign_share 6 /* Same as *_gmfn_foreign, but this is
+ for a privileged dom to
+ shared pages between two doms. */

and create a corresponding entry xsm_map_gmfn_foreign_share to the xsm structure, which will be filled with
the proposed policy.

Does this look good to you?

Cheers,

Zhongze Liu

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#12 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

2017-10-25 17:37 GMT+08:00 Zhongze Liu <[email protected]>:

Review

Quoted 7 lines

Hi,

My current plan is to add the following new MAPSPACE to public/memory.h:

(quoted diff) +3 -0
+#define XENMEMSPACE_gmfn_foreign_share 6 /* Same as *_gmfn_foreign, but this is
+                                            for a privileged dom to
+                                            shared pages between two doms. */

s/shared/share

Quoted 10 lines

and create a corresponding entry xsm_map_gmfn_foreign_share to the xsm structure, which will be filled with
the proposed policy.

Does this look good to you?

Cheers,

Zhongze Liu

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#13 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

In reply to Zhongze Liu

Review

Quoted 6 lines
Quoted 1 line
Quoted 1 line · On 25.10.17 at 11:37, <[email protected]> wrote:

My current plan is to add the following new MAPSPACE to public/memory.h:

(quoted diff) +3 -0
+#define XENMEMSPACE_gmfn_foreign_share 6 /* Same as *_gmfn_foreign, but this is
+                                            for a privileged dom to
+                                            shared pages between two doms. */

I think XENMEMSPACE_gmfn_share would suffice as a name.

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#14 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

In reply to Zhongze Liu
Quoted 58 lines · Zhongze Liu

The original dummy xsm_map_gmfn_foregin checks if source domain has the proper privileges over the target domain. Under this policy, it's not allowed if a Dom0 wants to map pages from one DomU to another, which restricts some useful yet not dangerous use cases of the API, such as sharing pages among DomU's by calling XENMEM_add_to_physmap from Dom0.

For the dummy xsm_map_gmfn_foregin, change to policy to: IFF the current domain has the proper privileges on (d) and (t), grant the access.

For the flask side: 1) Introduce a new av permission MMU__SHARE_MEM to denote if two domains can share memory through map_gmfn_foregin. 2) Change to hook to grant the access IFF the current domain has proper MMU privileges on (d) and (t), and MMU__SHARE_MEM is allowed between (d) and (t). 3) Modify the default xen.te to allow MMU__SHARE_MEM for normal domains that allow grant mapping/event channels.

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Daniel De Graaf <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* Change several if statements to the GCC '... = a ?: b' extention.
* lookup the current domain in the hooks instead of passing it as an arg

---
  tools/flask/policy/modules/xen.if   | 2 ++
  xen/include/xsm/dummy.h             | 3 ++-
  xen/xsm/flask/hooks.c               | 4 +++-
  xen/xsm/flask/policy/access_vectors | 4 ++++
  4 files changed, 11 insertions(+), 2 deletions(-)
tools/flask/policy/modules/xen.if +2 -0
index 55437496f6..3ffd1c6239 100644
@@ -127,6 +127,8 @@ define(`domain_comms', `
  	domain_event_comms($1, $2)
  	allow $1 $2:grant { map_read map_write copy unmap };
  	allow $2 $1:grant { map_read map_write copy unmap };
+	allow $1 $2:mmu share_mem;
+	allow $2 $1:mmu share_mem;
  ')
 
  # domain_self_comms(domain)
xen/include/xsm/dummy.h +0 -0
index b2cd56cdc5..65e7060ad5 100644

xen/include/xsm/dummy.h static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1, · line 521

Quoted 7 lines
xen/include/xsm/dummy.h +2 -1
@@ -516,7 +516,8 @@ static XSM_INLINE int xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,
  static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain *d, struct domain *t)
  {
      XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
  }

Same comment as below, the check between (current->domain) and (d) should be redundant with one higher up in the call stack. The check between (current->domain) and (t) should remain, although this *does* result in a relaxing of the existing permission checks on the call as Jan noted.

Quoted 6 lines
xen/include/xsm/dummy.h +0 -0
  static XSM_INLINE int xsm_hvm_param(XSM_DEFAULT_ARG struct domain *d, unsigned long op)
xen/xsm/flask/hooks.c +0 -0
index f01b4cfaaa..16103bafc9 100644

xen/xsm/flask/hooks.c static int flask_remove_from_physmap(struct domain *d1, struct domain *d2) · line 1205

Quoted 8 lines
xen/xsm/flask/hooks.c +3 -1
@@ -1199,7 +1199,9 @@ static int flask_remove_from_physmap(struct domain *d1, struct domain *d2)
 
  static int flask_map_gmfn_foreign(struct domain *d, struct domain *t)
  {
-    return domain_has_perm(d, t, SECCLASS_MMU, MMU__MAP_READ | MMU__MAP_WRITE);
+    return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__MAP_READ | MMU__MAP_WRITE) ?:
+        domain_has_perm(current->domain, t, SECCLASS_MMU, MMU__MAP_READ | MMU__MAP_WRITE) ?:
+        domain_has_perm(d, t, SECCLASS_MMU, MMU__SHARE_MEM);
  }

This is at least partially redundant with the higher-level permission checks needed to get to the xenmem_add_* functions (xatp_permission_check call in xen/common/memory.c, for example). That check already verifies the permission for (current->domain) to modify (d)'s page tables.

The other two checks here look correct.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#15 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Hi Daniel,

2017-10-20 1:36 GMT+08:00 Daniel De Graaf <[email protected]>:

Quoted 112 lines · Zhongze Liu
Quoted 69 lines

The original dummy xsm_map_gmfn_foregin checks if source domain has the proper
privileges over the target domain. Under this policy, it's not allowed if a Dom0
wants to map pages from one DomU to another, which restricts some useful yet not
dangerous use cases of the API, such as sharing pages among DomU's by calling
XENMEM_add_to_physmap from Dom0.

For the dummy xsm_map_gmfn_foregin, change to policy to: IFF the current domain
has the proper privileges on (d) and (t), grant the access.

For the flask side: 1) Introduce a new av permission MMU__SHARE_MEM to denote if
two domains can share memory through map_gmfn_foregin. 2) Change to hook to
grant the access IFF the current domain has proper MMU privileges on (d) and (t),
and MMU__SHARE_MEM is allowed between (d) and (t). 3) Modify the default xen.te
to allow MMU__SHARE_MEM for normal domains that allow grant mapping/event channels.

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Daniel De Graaf <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* Change several if statements to the GCC '... = a ?: b' extention.
* lookup the current domain in the hooks instead of passing it as an
arg

---
  tools/flask/policy/modules/xen.if   | 2 ++
  xen/include/xsm/dummy.h             | 3 ++-
  xen/xsm/flask/hooks.c               | 4 +++-
  xen/xsm/flask/policy/access_vectors | 4 ++++
  4 files changed, 11 insertions(+), 2 deletions(-)
tools/flask/policy/modules/xen.if +2 -0
index 55437496f6..3ffd1c6239 100644
@@ -127,6 +127,8 @@ define(`domain_comms', `
        domain_event_comms($1, $2)
        allow $1 $2:grant { map_read map_write copy unmap };
        allow $2 $1:grant { map_read map_write copy unmap };
+       allow $1 $2:mmu share_mem;
+       allow $2 $1:mmu share_mem;
  ')
    # domain_self_comms(domain)
xen/include/xsm/dummy.h +0 -0
index b2cd56cdc5..65e7060ad5 100644

xen/include/xsm/dummy.h static XSM_INLINE int · line 523

Quoted 9 lines
xen/include/xsm/dummy.h +2 -1
@@ -516,7 +516,8 @@ static XSM_INLINE int
 xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,
  static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain
 *d, struct domain *t)
  {
      XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
  }

Same comment as below, the check between (current->domain) and (d) should be redundant with one higher up in the call stack. The check between (current->domain) and (t) should remain, although this *does* result in a relaxing of the existing permission checks on the call as Jan noted.

Quoted 13 lines

static XSM_INLINE int xsm_hvm_param(XSM_DEFAULT_ARG struct domain *d,
unsigned long op)

xen/xsm/flask/hooks.c +1 -1
index f01b4cfaaa..16103bafc9 100644
@@ -1199,7 +1199,9 @@ static int flask_remove_from_physmap(struct domain
 *d1, struct domain *d2)
    static int flask_map_gmfn_foreign(struct domain *d, struct domain *t)
  {
-    return domain_has_perm(d, t, SECCLASS_MMU, MMU__MAP_READ |
 MMU__MAP_WRITE);
+    return domain_has_perm(current->domain, d, SECCLASS_MMU,
Quoted 5 lines

MMU__MAP_READ | MMU__MAP_WRITE) ?:
+ domain_has_perm(current->domain, t, SECCLASS_MMU, MMU__MAP_READ |
MMU__MAP_WRITE) ?:
+ domain_has_perm(d, t, SECCLASS_MMU, MMU__SHARE_MEM);
}

This is at least partially redundant with the higher-level permission checks needed to get to the xenmem_add_* functions (xatp_permission_check call in xen/common/memory.c, for example). That check already verifies the permission
for (current->domain) to modify (d)'s page tables.

Quoted 1 line

The other two checks here look correct.

Do you mean that the checks that verify the permission for (current->domain) to modify (d)'s page tables have already been done somewhere higher up in the call stack so that I can eliminate them in both hooks?

Cheers,

Zhongze Liu.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#16 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

2017-10-20 8:34 GMT+08:00 Zhongze Liu <[email protected]>:

Quoted 115 lines

Hi Daniel,

2017-10-20 1:36 GMT+08:00 Daniel De Graaf <[email protected]>:

Quoted 112 lines · Zhongze Liu
Quoted 69 lines

The original dummy xsm_map_gmfn_foregin checks if source domain has the proper
privileges over the target domain. Under this policy, it's not allowed if a Dom0
wants to map pages from one DomU to another, which restricts some useful yet not
dangerous use cases of the API, such as sharing pages among DomU's by calling
XENMEM_add_to_physmap from Dom0.

For the dummy xsm_map_gmfn_foregin, change to policy to: IFF the current domain
has the proper privileges on (d) and (t), grant the access.

For the flask side: 1) Introduce a new av permission MMU__SHARE_MEM to denote if
two domains can share memory through map_gmfn_foregin. 2) Change to hook to
grant the access IFF the current domain has proper MMU privileges on (d) and (t),
and MMU__SHARE_MEM is allowed between (d) and (t). 3) Modify the default xen.te
to allow MMU__SHARE_MEM for normal domains that allow grant mapping/event channels.

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Daniel De Graaf <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* Change several if statements to the GCC '... = a ?: b' extention.
* lookup the current domain in the hooks instead of passing it as an
arg

---
  tools/flask/policy/modules/xen.if   | 2 ++
  xen/include/xsm/dummy.h             | 3 ++-
  xen/xsm/flask/hooks.c               | 4 +++-
  xen/xsm/flask/policy/access_vectors | 4 ++++
  4 files changed, 11 insertions(+), 2 deletions(-)
tools/flask/policy/modules/xen.if +2 -0
index 55437496f6..3ffd1c6239 100644
@@ -127,6 +127,8 @@ define(`domain_comms', `
        domain_event_comms($1, $2)
        allow $1 $2:grant { map_read map_write copy unmap };
        allow $2 $1:grant { map_read map_write copy unmap };
+       allow $1 $2:mmu share_mem;
+       allow $2 $1:mmu share_mem;
  ')
    # domain_self_comms(domain)
xen/include/xsm/dummy.h +0 -0
index b2cd56cdc5..65e7060ad5 100644

xen/include/xsm/dummy.h static XSM_INLINE int · line 523

Quoted 9 lines
xen/include/xsm/dummy.h +2 -1
@@ -516,7 +516,8 @@ static XSM_INLINE int
 xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,
  static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain
 *d, struct domain *t)
  {
      XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
  }

Same comment as below, the check between (current->domain) and (d) should be redundant with one higher up in the call stack. The check between (current->domain) and (t) should remain, although this *does* result in a relaxing of the existing permission checks on the call as Jan noted.

Quoted 13 lines

static XSM_INLINE int xsm_hvm_param(XSM_DEFAULT_ARG struct domain *d,
unsigned long op)

xen/xsm/flask/hooks.c +1 -1
index f01b4cfaaa..16103bafc9 100644
@@ -1199,7 +1199,9 @@ static int flask_remove_from_physmap(struct domain
 *d1, struct domain *d2)
    static int flask_map_gmfn_foreign(struct domain *d, struct domain *t)
  {
-    return domain_has_perm(d, t, SECCLASS_MMU, MMU__MAP_READ |
 MMU__MAP_WRITE);
+    return domain_has_perm(current->domain, d, SECCLASS_MMU,
Quoted 5 lines

MMU__MAP_READ | MMU__MAP_WRITE) ?:
+ domain_has_perm(current->domain, t, SECCLASS_MMU, MMU__MAP_READ |
MMU__MAP_WRITE) ?:
+ domain_has_perm(d, t, SECCLASS_MMU, MMU__SHARE_MEM);
}

This is at least partially redundant with the higher-level permission checks needed to get to the xenmem_add_* functions (xatp_permission_check call in xen/common/memory.c, for example). That check already verifies the permission
for (current->domain) to modify (d)'s page tables.

Quoted 5 lines
Quoted 1 line

The other two checks here look correct.

Do you mean that the checks that verify the permission for (current->domain) to modify (d)'s page tables have already been done somewhere higher up in the call stack so that I can eliminate them in both hooks?

Although xatp_permission_chec() does check (current->domain)'s permission over (d), I'm not sure if this is the case for all the call paths that would finally lead to map_gmfn_foregin().
If the answer is yes, I would happily remove the redundant checks.

Cheers,

Zhongze Liu.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#17 lore raw

Re: [PATCH v3 2/7] xsm: flask: change the dummy xsm policy and flask hook for map_gmfn_foregin

Quoted 122 lines · Zhongze Liu

2017-10-20 8:34 GMT+08:00 Zhongze Liu <[email protected]>:

Quoted 115 lines

Hi Daniel,

2017-10-20 1:36 GMT+08:00 Daniel De Graaf <[email protected]>:

Quoted 112 lines · Zhongze Liu
Quoted 69 lines

The original dummy xsm_map_gmfn_foregin checks if source domain has the proper
privileges over the target domain. Under this policy, it's not allowed if a Dom0
wants to map pages from one DomU to another, which restricts some useful yet not
dangerous use cases of the API, such as sharing pages among DomU's by calling
XENMEM_add_to_physmap from Dom0.

For the dummy xsm_map_gmfn_foregin, change to policy to: IFF the current domain
has the proper privileges on (d) and (t), grant the access.

For the flask side: 1) Introduce a new av permission MMU__SHARE_MEM to denote if
two domains can share memory through map_gmfn_foregin. 2) Change to hook to
grant the access IFF the current domain has proper MMU privileges on (d) and (t),
and MMU__SHARE_MEM is allowed between (d) and (t). 3) Modify the default xen.te
to allow MMU__SHARE_MEM for normal domains that allow grant mapping/event channels.

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Daniel De Graaf <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* Change several if statements to the GCC '... = a ?: b' extention.
* lookup the current domain in the hooks instead of passing it as an
arg

---
   tools/flask/policy/modules/xen.if   | 2 ++
   xen/include/xsm/dummy.h             | 3 ++-
   xen/xsm/flask/hooks.c               | 4 +++-
   xen/xsm/flask/policy/access_vectors | 4 ++++
   4 files changed, 11 insertions(+), 2 deletions(-)
tools/flask/policy/modules/xen.if +2 -0
index 55437496f6..3ffd1c6239 100644
@@ -127,6 +127,8 @@ define(`domain_comms', `
         domain_event_comms($1, $2)
         allow $1 $2:grant { map_read map_write copy unmap };
         allow $2 $1:grant { map_read map_write copy unmap };
+       allow $1 $2:mmu share_mem;
+       allow $2 $1:mmu share_mem;
   ')
     # domain_self_comms(domain)
xen/include/xsm/dummy.h +0 -0
index b2cd56cdc5..65e7060ad5 100644

xen/include/xsm/dummy.h static XSM_INLINE int · line 523

Quoted 9 lines
xen/include/xsm/dummy.h +2 -1
@@ -516,7 +516,8 @@ static XSM_INLINE int
 xsm_remove_from_physmap(XSM_DEFAULT_ARG struct domain *d1,
   static XSM_INLINE int xsm_map_gmfn_foreign(XSM_DEFAULT_ARG struct domain
 *d, struct domain *t)
   {
       XSM_ASSERT_ACTION(XSM_TARGET);
-    return xsm_default_action(action, d, t);
+    return xsm_default_action(action, current->domain, d) ?:
+        xsm_default_action(action, current->domain, t);
   }

Same comment as below, the check between (current->domain) and (d) should be redundant with one higher up in the call stack. The check between (current->domain) and (t) should remain, although this *does* result in a relaxing of the existing permission checks on the call as Jan noted.

Quoted 16 lines

static XSM_INLINE int xsm_hvm_param(XSM_DEFAULT_ARG struct domain *d,
unsigned long op)

xen/xsm/flask/hooks.c +1 -1
index f01b4cfaaa..16103bafc9 100644
@@ -1199,7 +1199,9 @@ static int flask_remove_from_physmap(struct domain
 *d1, struct domain *d2)
     static int flask_map_gmfn_foreign(struct domain *d, struct domain *t)
   {
-    return domain_has_perm(d, t, SECCLASS_MMU, MMU__MAP_READ |
 MMU__MAP_WRITE);
+    return domain_has_perm(current->domain, d, SECCLASS_MMU,

MMU__MAP_READ | MMU__MAP_WRITE) ?:
+ domain_has_perm(current->domain, t, SECCLASS_MMU, MMU__MAP_READ |
MMU__MAP_WRITE) ?:

Quoted 2 lines
+        domain_has_perm(d, t, SECCLASS_MMU, MMU__SHARE_MEM);
   }

This is at least partially redundant with the higher-level permission checks needed to get to the xenmem_add_* functions (xatp_permission_check call in xen/common/memory.c, for example). That check already verifies the permission
for (current->domain) to modify (d)'s page tables.

Quoted 5 lines
Quoted 1 line

The other two checks here look correct.

Do you mean that the checks that verify the permission for (current->domain) to modify (d)'s page tables have already been done somewhere higher up in the call stack so that I can eliminate them in both hooks?

Quoted 8 lines

Although xatp_permission_chec() does check (current->domain)'s permission over (d), I'm not sure if this is the case for all the call paths that would finally lead to map_gmfn_foregin().
If the answer is yes, I would happily remove the redundant checks.

Cheers,

Zhongze Liu.

If this were not the case, there would be other security bugs for the other XENMAPSPACE_* flags that don't have their own XSM check at this level. Last time I checked, all paths that led here have already gone through such a check.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#18 lore raw

PATCH v3 3/7 libxl: introduce a new structure to represent static shared memory regions

In reply to Zhongze Liu

Add a new structure to the IDL familiy to represent static shared memory regions as proposed in the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Wei Liu <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>
---
 tools/libxl/libxl.h         |  4 ++++
 tools/libxl/libxl_types.idl | 32 ++++++++++++++++++++++++++++++--
 2 files changed, 34 insertions(+), 2 deletions(-)
tools/libxl/libxl.h +4 -0
index 5e9aed739d..5fbbe266e5 100644
@@ -2320,6 +2320,10 @@ int libxl_fd_set_nonblock(libxl_ctx *ctx, int fd, int nonblock);
 int libxl_qemu_monitor_command(libxl_ctx *ctx, uint32_t domid,
                                const char *command_line, char **output);
 
+/* Constants for libxl_static_shm */
+#define LIBXL_SSHM_RANGE_UNKNOWN UINT64_MAX
+#define LIBXL_SSHM_ID_MAXLEN    128
+
 #include <libxl_event.h>
 
 #endif /* LIBXL_H */
tools/libxl/libxl_types.idl +30 -2
index a239324341..78cd2696b0 100644
@@ -559,10 +559,10 @@ libxl_domain_build_info = Struct("domain_build_info",[
                                        ("keymap",           string),
                                        ("sdl",              libxl_sdl_info),
                                        ("spice",            libxl_spice_info),
-                                       
+
                                        ("gfx_passthru",     libxl_defbool),
                                        ("gfx_passthru_kind", libxl_gfx_passthru_kind),
-                                       
+
                                        ("serial",           string),
                                        ("boot",             string),
                                        ("usb",              libxl_defbool),
@@ -812,6 +812,33 @@ libxl_device_vdispl = Struct("device_vdispl", [
     ("connectors", Array(libxl_connector_param, "num_connectors"))
     ])
 
+libxl_sshm_cachepolicy = Enumeration("sshm_cachepolicy", [
+    (-1, "UNKNOWN"),
+    (0,  "ARM_NORMAL"),  # ARM policies should be < 32
+    (32,  "X86_NORMAL"), # X86 policies should be >= 32
+    ], init_val = "LIBXL_SSHM_CHCHE_POLICY_UNKNOWN")
+
+libxl_sshm_prot = Enumeration("sshm_prot", [
+    (-1, "UNKNOWN"),
+    (3,  "RW"),
+    ], init_val = "LIBXL_SSHM_PROT_UNKNOWN")
+
+libxl_sshm_role = Enumeration("sshm_role", [
+    (-1, "UNKNOWN"),
+    (0,  "MASTER"),
+    (1,  "SLAVE"),
+    ], init_val = "LIBXL_SSHM_ROLE_UNKNOWN")
+
+libxl_static_shm = Struct("static_shm", [
+    ("id", string),
+    ("offset", uint64, {'init_val': 'LIBXL_SSHM_RANGE_UNKNOWN'}),
+    ("begin", uint64, {'init_val': 'LIBXL_SSHM_RANGE_UNKNOWN'}),
+    ("end", uint64, {'init_val': 'LIBXL_SSHM_RANGE_UNKNOWN'}),
+    ("prot", libxl_sshm_prot, {'init_val': 'LIBXL_SSHM_PROT_UNKNOWN'}),
+    ("cache_policy", libxl_sshm_cachepolicy, {'init_val': 'LIBXL_SSHM_CACHEPOLICY_UNKNOWN'}),
+    ("role", libxl_sshm_role, {'init_val': 'LIBXL_SSHM_ROLE_UNKNOWN'}),
+])
+
 libxl_domain_config = Struct("domain_config", [
     ("c_info", libxl_domain_create_info),
     ("b_info", libxl_domain_build_info),
@@ -831,6 +858,7 @@ libxl_domain_config = Struct("domain_config", [
     ("channels", Array(libxl_device_channel, "num_channels")),
     ("usbctrls", Array(libxl_device_usbctrl, "num_usbctrls")),
     ("usbdevs", Array(libxl_device_usbdev, "num_usbdevs")),
+    ("sshms", Array(libxl_static_shm, "num_sshms")),
 
     ("on_poweroff", libxl_action_on_shutdown),
     ("on_reboot", libxl_action_on_shutdown),
Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Acked-by on v3 3/7
#19 lore raw

Re: [PATCH v3 3/7] libxl: introduce a new structure to represent static shared memory regions

Quoted 8 lines · Zhongze Liu

Add a new structure to the IDL familiy to represent static shared memory regions as proposed in the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#20 lore raw

PATCH v3 4/7 libxl: support mapping static shared memory areas during domain creation

In reply to Zhongze Liu

Add libxl__sshm_add to map shared pages from one DomU to another, The mapping process involves the follwing steps:

* Set defaults and check for further errors in the static_shm configs:
overlapping areas, invalid ranges, duplicated master domain, no master domain etc.
* Write infomation of static shared memory areas into the appropriate xenstore paths.
* Use xc_domain_add_to_physmap_batch to do the page sharing.
* Set the refcount of the shared region accordingly

Temporarily mark this as unsupported on x86 because calling p2m_add_foregin on two domU's is currently not allowd on x86 (see the comments in x86/mm/p2m.c:p2m_add_foregin for more details).

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Wei Liu <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* unmap the successfully mapped pages whenever rc != 0

---
 tools/libxl/Makefile         |   2 +-
 tools/libxl/libxl_arch.h     |   6 +
 tools/libxl/libxl_arm.c      |  15 ++
 tools/libxl/libxl_create.c   |  27 +++
 tools/libxl/libxl_internal.h |  13 ++
 tools/libxl/libxl_sshm.c     | 395 +++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_x86.c      |  18 ++
 7 files changed, 475 insertions(+), 1 deletion(-)
 create mode 100644 tools/libxl/libxl_sshm.c
tools/libxl/Makefile +1 -1
index 5a861f72cb..91bc70cda2 100644
@@ -139,7 +139,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
 			libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
 			libxl_cpupool.o libxl_mem.o libxl_sched.o libxl_tmem.o \
-			libxl_9pfs.o libxl_domain.o libxl_vdispl.o \
+			libxl_9pfs.o libxl_domain.o libxl_vdispl.o libxl_sshm.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
tools/libxl/libxl_arch.h +6 -0
index 784ec7f609..11433fe466 100644
@@ -78,6 +78,12 @@ int libxl__arch_extra_memory(libxl__gc *gc,
                              const libxl_domain_build_info *info,
                              uint64_t *out);
 
+_hidden
+bool libxl__arch_domain_support_sshm(const libxl_domain_build_info *b_info);
+
+_hidden
+int libxl__arch_domain_sshm_cachepolicy_setdefault(libxl_static_shm *sshm);
+
 #if defined(__i386__) || defined(__x86_64__)
 
 #define LAPIC_BASE_ADDRESS  0xfee00000
tools/libxl/libxl_arm.c +15 -0
index de1840bece..d687dad0bd 100644
@@ -1154,6 +1154,21 @@ void libxl__arch_domain_build_info_acpi_setdefault(
     libxl_defbool_setdefault(&b_info->acpi, false);
 }
 
+bool libxl__arch_domain_support_sshm(const libxl_domain_build_info *b_info)
+{
+    return true;
+}
+
+int libxl__arch_domain_sshm_cachepolicy_setdefault(libxl_static_shm *sshm)
+{
+    if (sshm->cache_policy == LIBXL_SSHM_CACHEPOLICY_UNKNOWN)
+        sshm->cache_policy = LIBXL_SSHM_CACHEPOLICY_ARM_NORMAL;
+    if (sshm->cache_policy >= LIBXL_SSHM_CACHEPOLICY_X86_NORMAL)
+        return ERROR_INVAL;
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
tools/libxl/libxl_create.c +27 -0
index f15fb215c2..fecc873b7a 100644
@@ -514,6 +514,14 @@ int libxl__domain_build(libxl__gc *gc,
         ret = ERROR_INVAL;
         goto out;
     }
+
+    /* the p2m has been setup, we could map the static shared memory now. */
+    ret = libxl__sshm_add(gc, domid, d_config->sshms, d_config->num_sshms);
+    if (ret != 0) {
+        LOG(ERROR, "failed to map static shared memory");
+        goto out;
+    }
+
     ret = libxl__build_post(gc, domid, info, state, vments, localents);
 out:
     return ret;
@@ -939,6 +947,25 @@ static void initiate_domain_create(libxl__egc *egc,
         goto error_out;
     }
 
+    if (d_config->num_sshms != 0 &&
+        !libxl__arch_domain_support_sshm(&d_config->b_info)) {
+        LOGD(ERROR, domid, "static_shm is not supported by this domain type.");
+        ret = ERROR_INVAL;
+        goto error_out;
+    }
+
+    for (i = 0; i < d_config->num_sshms; ++i) {
+        ret = libxl__sshm_setdefault(gc, domid, &d_config->sshms[i]);
+        if (ret) {
+            LOGD(ERROR, domid, "Unable to set defaults for static shm");
+            goto error_out;
+        }
+    }
+
+    ret = libxl__sshm_check_overlap(gc, domid,
+                                    d_config->sshms, d_config->num_sshms);
+    if (ret) goto error_out;
+
     ret = libxl__domain_make(gc, d_config, &domid, &state->config);
     if (ret) {
         LOGD(ERROR, domid, "cannot make domain: %d", ret);
tools/libxl/libxl_internal.h +13 -0
index 45e6df6c82..fc28191625 100644
@@ -4350,6 +4350,19 @@ static inline bool libxl__string_is_default(char **s)
 }
 #endif
 
+/*
+ * Set up static shared ram pages for HVM domains to communicate
+ *
+ * This function should only be called after the memory map is constructed
+ * and before any further memory access. */
+_hidden int libxl__sshm_add(libxl__gc *gc, uint32_t domid,
+                            libxl_static_shm *sshm, int len);
+
+_hidden int libxl__sshm_check_overlap(libxl__gc *gc, uint32_t domid,
+                                      libxl_static_shm *sshms, int len);
+_hidden int libxl__sshm_setdefault(libxl__gc *gc, uint32_t domid,
+                                   libxl_static_shm *sshm);
+
 /*
  * Local variables:
  * mode: C
tools/libxl/libxl_sshm.c new file +395 -0

395 lines not on this page · raw message

tools/libxl/libxl_x86.c +18 -0
index 5f91fe4f92..450fb3d354 100644
@@ -596,6 +596,24 @@ void libxl__arch_domain_build_info_acpi_setdefault(
     libxl_defbool_setdefault(&b_info->acpi, true);
 }
 
+bool libxl__arch_domain_support_sshm(const libxl_domain_build_info *b_info)
+{
+    /* FIXME: Mark this as unsupported for calling p2m_add_foreign on two
+     * DomU's is currently not allowd on x86, see the comments in
+     * x86/mm/p2m.c: p2m_add_foreign */
+     return false;
+}
+
+int libxl__arch_domain_sshm_cachepolicy_setdefault(libxl_static_shm *sshm)
+{
+    if (sshm->cache_policy == LIBXL_SSHM_CACHEPOLICY_UNKNOWN)
+        sshm->cache_policy = LIBXL_SSHM_CACHEPOLICY_X86_NORMAL;
+    if (sshm->cache_policy < LIBXL_SSHM_CACHEPOLICY_X86_NORMAL)
+        return ERROR_INVAL;
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
#21 lore raw

Re: [PATCH v3 4/7] libxl: support mapping static shared memory areas during domain creation

Quoted 22 lines · Zhongze Liu

Add libxl__sshm_add to map shared pages from one DomU to another, The mapping process involves the follwing steps:

* Set defaults and check for further errors in the static_shm configs:
overlapping areas, invalid ranges, duplicated master domain, no master domain etc.
* Write infomation of static shared memory areas into the appropriate xenstore paths.
* Use xc_domain_add_to_physmap_batch to do the page sharing.
* Set the refcount of the shared region accordingly

Temporarily mark this as unsupported on x86 because calling p2m_add_foregin on two domU's is currently not allowd on x86 (see the comments in x86/mm/p2m.c:p2m_add_foregin for more details).

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Quoted 8 lines
Cc Wei Liu <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* unmap the successfully mapped pages whenever rc != 0

A general note: please properly capitalise the comments.

Quoted 15 lines
---
 tools/libxl/Makefile         |   2 +-
 tools/libxl/libxl_arch.h     |   6 +
 tools/libxl/libxl_arm.c      |  15 ++
 tools/libxl/libxl_create.c   |  27 +++
 tools/libxl/libxl_internal.h |  13 ++
 tools/libxl/libxl_sshm.c     | 395 +++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_x86.c      |  18 ++
 7 files changed, 475 insertions(+), 1 deletion(-)
 create mode 100644 tools/libxl/libxl_sshm.c
tools/libxl/Makefile +0 -0
index 5a861f72cb..91bc70cda2 100644

[...]

Quoted 24 lines
tools/libxl/Makefile +24 -0
+
+/* check if the sshm slave configs in @sshm overlap */
+int libxl__sshm_check_overlap(libxl__gc *gc, uint32_t domid,
+                                     libxl_static_shm *sshms, int len)
+{
+
+    const libxl_static_shm **slave_sshms = NULL;
+    int num_slaves;
+    int i;
+
+    if (!len) return 0;
+
+    slave_sshms = libxl__calloc(gc, len, sizeof(slave_sshms[0]));
+    num_slaves = 0;
+    for (i = 0; i < len; ++i) {
+        if (sshms[i].role == LIBXL_SSHM_ROLE_SLAVE)
+            slave_sshms[num_slaves++] = sshms + i;
+    }
+    qsort(slave_sshms, num_slaves, sizeof(slave_sshms[0]), sshm_range_cmp);
+
+    for (i = 0; i < num_slaves - 1; ++i) {
+        if (slave_sshms[i+1]->begin < slave_sshms[i]->end) {
+            SSHM_ERROR(domid, slave_sshms[i+1]->id, "slave ranges overlap.");
+            return ERROR_INVAL;

tools/libxl/Makefile

Quoted 10 lines
tools/libxl/Makefile +10 -0
+        }
+    }
+
+    return 0;
+}
+
+/*   libxl__sshm_do_map -- map pages into slave's physmap
+ *
+ *   This functions maps
+ *     mater gfn: [@msshm->begin + @sshm->offset, @msshm->end + @sshm->offset)

"master"

This is confusing. What if offset is not page aligned?

Quoted 82 lines

+ * into
+ * slave gfn: [@sshm->begin, @sshm->end)
+ *
+ * The gfns of the pages that are successfully mapped will be stored
+ * in @mapped, and the number of the gfns will be stored in @nmapped.
+ *
+ * The caller have to guarentee that sshm->begin < sshm->end */

tools/libxl/Makefile +75 -0
+static int libxl__sshm_do_map(libxl__gc *gc, uint32_t mid, uint32_t sid,
+                              libxl_static_shm *sshm, libxl_static_shm *msshm,
+                              xen_pfn_t *mapped, unsigned int *nmapped)
+{
+    int rc;
+    int i;
+    unsigned int num_mpages, num_spages, num_success, offset;
+    int *errs;
+    xen_ulong_t *idxs;
+    xen_pfn_t *gpfns;
+
+    num_mpages = (msshm->end - msshm->begin) >> XC_PAGE_SHIFT;
+    num_spages = (sshm->end - sshm->begin) >> XC_PAGE_SHIFT;
+    offset = sshm->offset >> XC_PAGE_SHIFT;
+
+    /* Check range. Test offset < mpages first to avoid overflow */
+    if ((offset >= num_mpages) || (num_mpages - offset < num_spages)) {
+        SSHM_ERROR(sid, sshm->id, "exceeds master's address space.");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    /* fill out the pfn's and do the mapping */
+    errs = libxl__calloc(gc, num_spages, sizeof(int));
+    idxs = libxl__calloc(gc, num_spages, sizeof(xen_ulong_t));
+    gpfns = libxl__calloc(gc, num_spages, sizeof(xen_pfn_t));
+    for (i = 0; i < num_spages; i++) {
+        idxs[i] = (msshm->begin >> XC_PAGE_SHIFT) + offset + i;
+        gpfns[i]= (sshm->begin >> XC_PAGE_SHIFT) + i;
+    }
+    rc = xc_domain_add_to_physmap_batch(CTX->xch,
+                                        sid, mid,
+                                        XENMAPSPACE_gmfn_foreign,
+                                        num_spages,
+                                        idxs, gpfns, errs);
+
+    num_success = 0;
+    for (i = 0; i < num_spages; i++) {
+        if (errs[i]) {
+            SSHM_ERROR(sid, sshm->id,
+                       "can't map at address 0x%"PRIx64".",
+                       gpfns[i] << XC_PAGE_SHIFT);
+            rc = ERROR_FAIL;
+        } else {
+            mapped[num_success++] = gpfns[i];
+        }
+    }
+    *nmapped = num_success;
+    if (rc) goto out;
+
+    rc = 0;
+out:
+    return rc;
+}
+
+static int libxl__sshm_incref(libxl__gc *gc, xs_transaction_t xt,
+                              const char *sshm_path)
+{
+    int rc, count;
+    const char *count_path, *count_string;
+
+    count_path = GCSPRINTF("%s/users", sshm_path);
+    rc = libxl__xs_read_checked(gc, xt, count_path, &count_string);
+    if (rc) goto out;
+    count = atoi(count_string);
+
+    count_string = GCSPRINTF("%d", count+1);
+    rc = libxl__xs_write_checked(gc, xt, count_path, count_string);
+    if (rc) goto out;
+
+    rc = 0;
+out:
+    return rc;
+}
+

[...]

Quoted 21 lines
tools/libxl/Makefile +21 -0
+
+        /* all checks passed, do the job */
+        if (!isretry) {
+            rc = libxl__sshm_do_map(gc, master_domid, domid,
+                                    sshm, &master_sshm,
+                                    mapped, &nmapped);
+            if (rc) goto out;
+        }
+
+        /* write the result to xenstore and commit */
+        rc = libxl__xs_write_checked(gc, xt, dom_role_path, "slave");
+        if (rc) goto out;
+        rc = libxl__xs_writev(gc, xt, slave_path, ents);
+        if (rc) goto out;
+        rc = libxl__sshm_incref(gc, xt, sshm_path);
+        if (rc) goto out;
+
+        rc = libxl__xs_transaction_commit(gc, &xt);
+        if (!rc) break;
+        if (rc < 0) goto out;
+        isretry = true;

tools/libxl/Makefile

Quoted 10 lines
tools/libxl/Makefile +10 -0
+    }
+
+    rc = 0;
+out:
+    if (rc) {
+        /* role back successfully mapped pages */
+        SSHM_ERROR(domid, sshm->id, "failed to map some pages, cancelling.");
+        for (i = 0; i < nmapped; i++) {
+            xc_domain_remove_from_physmap(CTX->xch, domid, mapped[i]);
+        }

It is possible to get here when the first attempt of mapping has failed. The do_map function can return early before it modifies nmapped. At first glance this code snippet is buggy.

I would suggest you change isretry to mapped and adjust the predicate for rolling back.

Quoted 32 lines
tools/libxl/Makefile +32 -0
+    }
+
+    libxl__xs_transaction_abort(gc, &xt);
+
+    return rc;
+}
+
+static int libxl__sshm_add_master(libxl__gc *gc, uint32_t domid,
+                                  libxl_static_shm *sshm)
+{
+    int rc;
+    const char *sshm_path, *dom_path, *dom_role_path;
+    char *ents[13];
+    struct xs_permissions noperm;
+    xs_transaction_t xt = XBT_NULL;
+
+    sshm_path = SSHM_PATH(sshm->id);
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    /* the domain should be in xenstore by now */
+    assert(dom_path);
+    dom_role_path = GCSPRINTF("%s/static_shm/%s/role", dom_path, sshm->id);
+
+    /* prepare the xenstore entries */
+    ents[0] = "master";
+    ents[1] = GCSPRINTF("%"PRIu32, domid);
+    ents[2] = "begin";
+    ents[3] = GCSPRINTF("0x%"PRIx64, sshm->begin);
+    ents[4] = "end";
+    ents[5] = GCSPRINTF("0x%"PRIx64, sshm->end);
+    ents[6] = "prot";
+    ents[7] = libxl__strdup(gc, libxl_sshm_prot_to_string(sshm->prot));
+    ents[8] = "cache_policy";

tools/libxl/Makefile

Quoted 10 lines
tools/libxl/Makefile +10 -0
+    ents[9] = libxl__strdup(gc,
+                            libxl_sshm_cachepolicy_to_string(sshm->cache_policy));
+    ents[10] = "users";
+    ents[11] = "1";
+    ents[12] = NULL;
+
+    /* could only be accessed by Dom0 */
+    noperm.id = 0;
+    noperm.perms = XS_PERM_NONE;
+

The owner of the path is going to be Dom0 and all other domains have no permission, which matches the comment.

Do you not want domid to be able to read? If you don't want it to read from the path, why not put in under some other paths like /libxl/?

Quoted 34 lines
tools/libxl/Makefile +34 -0
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &xt);
+        if (rc) goto out;
+
+        if (!libxl__xs_read(gc, xt, sshm_path)) {
+            /* every ID can appear in each domain at most once */
+            if (libxl__xs_read(gc, xt, dom_role_path)) {
+                SSHM_ERROR(domid, sshm->id,
+                           "domain tried to map the same ID twice.");
+                rc = ERROR_FAIL;
+                goto out;
+            }
+            rc = libxl__xs_write_checked(gc, xt, dom_role_path, "master");
+            if (rc) goto out;;
+
+            libxl__xs_mknod(gc, xt, sshm_path, &noperm, 1);
+            libxl__xs_writev(gc, xt, sshm_path, ents);
+        } else {
+            SSHM_ERROR(domid, sshm->id, "can only have one master.");
+            rc = ERROR_FAIL;
+            goto out;
+        }
+
+        rc = libxl__xs_transaction_commit(gc, &xt);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    rc = 0;
+out:
+    libxl__xs_transaction_abort(gc, &xt);
+    return rc;
+}
+

[...]

tools/libxl/libxl_x86.c void libxl__arch_domain_build_info_acpi_setdefault( · line 603

Quoted 13 lines
tools/libxl/libxl_x86.c +5 -0
index 5f91fe4f92..450fb3d354 100644
@@ -596,6 +596,24 @@ void libxl__arch_domain_build_info_acpi_setdefault(
     libxl_defbool_setdefault(&b_info->acpi, true);
 }
 
+bool libxl__arch_domain_support_sshm(const libxl_domain_build_info *b_info)
+{
+    /* FIXME: Mark this as unsupported for calling p2m_add_foreign on two
+     * DomU's is currently not allowd on x86, see the comments in
+     * x86/mm/p2m.c: p2m_add_foreign */

Move the */ to a new line please. And add "." after "p2m_add_foreign".

Quoted 19 lines
tools/libxl/libxl_x86.c +13 -0
+     return false;
+}
+
+int libxl__arch_domain_sshm_cachepolicy_setdefault(libxl_static_shm *sshm)
+{
+    if (sshm->cache_policy == LIBXL_SSHM_CACHEPOLICY_UNKNOWN)
+        sshm->cache_policy = LIBXL_SSHM_CACHEPOLICY_X86_NORMAL;
+    if (sshm->cache_policy < LIBXL_SSHM_CACHEPOLICY_X86_NORMAL)
+        return ERROR_INVAL;
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
Signature · 1 line
2.14.2

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#22 lore raw

Re: [PATCH v3 4/7] libxl: support mapping static shared memory areas during domain creation

Hi Wei,

2017-11-01 23:55 GMT+08:00 Wei Liu <[email protected]>:

Quoted 88 lines · Zhongze Liu
Quoted 22 lines

Add libxl__sshm_add to map shared pages from one DomU to another, The mapping process involves the follwing steps:

* Set defaults and check for further errors in the static_shm configs:
overlapping areas, invalid ranges, duplicated master domain, no master domain etc.
* Write infomation of static shared memory areas into the appropriate xenstore paths.
* Use xc_domain_add_to_physmap_batch to do the page sharing.
* Set the refcount of the shared region accordingly

Temporarily mark this as unsupported on x86 because calling p2m_add_foregin on two domU's is currently not allowd on x86 (see the comments in x86/mm/p2m.c:p2m_add_foregin for more details).

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Quoted 8 lines
Cc Wei Liu <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>

---
V3:
* unmap the successfully mapped pages whenever rc != 0

A general note: please properly capitalise the comments.

Quoted 15 lines
---
 tools/libxl/Makefile         |   2 +-
 tools/libxl/libxl_arch.h     |   6 +
 tools/libxl/libxl_arm.c      |  15 ++
 tools/libxl/libxl_create.c   |  27 +++
 tools/libxl/libxl_internal.h |  13 ++
 tools/libxl/libxl_sshm.c     | 395 +++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_x86.c      |  18 ++
 7 files changed, 475 insertions(+), 1 deletion(-)
 create mode 100644 tools/libxl/libxl_sshm.c
tools/libxl/Makefile +0 -0
index 5a861f72cb..91bc70cda2 100644

[...]

Quoted 24 lines
tools/libxl/Makefile +24 -0
+
+/* check if the sshm slave configs in @sshm overlap */
+int libxl__sshm_check_overlap(libxl__gc *gc, uint32_t domid,
+                                     libxl_static_shm *sshms, int len)
+{
+
+    const libxl_static_shm **slave_sshms = NULL;
+    int num_slaves;
+    int i;
+
+    if (!len) return 0;
+
+    slave_sshms = libxl__calloc(gc, len, sizeof(slave_sshms[0]));
+    num_slaves = 0;
+    for (i = 0; i < len; ++i) {
+        if (sshms[i].role == LIBXL_SSHM_ROLE_SLAVE)
+            slave_sshms[num_slaves++] = sshms + i;
+    }
+    qsort(slave_sshms, num_slaves, sizeof(slave_sshms[0]), sshm_range_cmp);
+
+    for (i = 0; i < num_slaves - 1; ++i) {
+        if (slave_sshms[i+1]->begin < slave_sshms[i]->end) {
+            SSHM_ERROR(domid, slave_sshms[i+1]->id, "slave ranges overlap.");
+            return ERROR_INVAL;

tools/libxl/Makefile

Quoted 10 lines
tools/libxl/Makefile +10 -0
+        }
+    }
+
+    return 0;
+}
+
+/*   libxl__sshm_do_map -- map pages into slave's physmap
+ *
+ *   This functions maps
+ *     mater gfn: [@msshm->begin + @sshm->offset, @msshm->end + @sshm->offset)

"master"

Quoted 1 line

This is confusing. What if offset is not page aligned?

No, it will always be page-aligned. This was documented in the man page and also checked
in the corresponding libxlu_* function.

Quoted 120 lines
Quoted 83 lines

+ * into
+ * slave gfn: [@sshm->begin, @sshm->end)
+ *
+ * The gfns of the pages that are successfully mapped will be stored
+ * in @mapped, and the number of the gfns will be stored in @nmapped.
+ *
+ * The caller have to guarentee that sshm->begin < sshm->end */

tools/libxl/Makefile +75 -0
+static int libxl__sshm_do_map(libxl__gc *gc, uint32_t mid, uint32_t sid,
+                              libxl_static_shm *sshm, libxl_static_shm *msshm,
+                              xen_pfn_t *mapped, unsigned int *nmapped)
+{
+    int rc;
+    int i;
+    unsigned int num_mpages, num_spages, num_success, offset;
+    int *errs;
+    xen_ulong_t *idxs;
+    xen_pfn_t *gpfns;
+
+    num_mpages = (msshm->end - msshm->begin) >> XC_PAGE_SHIFT;
+    num_spages = (sshm->end - sshm->begin) >> XC_PAGE_SHIFT;
+    offset = sshm->offset >> XC_PAGE_SHIFT;
+
+    /* Check range. Test offset < mpages first to avoid overflow */
+    if ((offset >= num_mpages) || (num_mpages - offset < num_spages)) {
+        SSHM_ERROR(sid, sshm->id, "exceeds master's address space.");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    /* fill out the pfn's and do the mapping */
+    errs = libxl__calloc(gc, num_spages, sizeof(int));
+    idxs = libxl__calloc(gc, num_spages, sizeof(xen_ulong_t));
+    gpfns = libxl__calloc(gc, num_spages, sizeof(xen_pfn_t));
+    for (i = 0; i < num_spages; i++) {
+        idxs[i] = (msshm->begin >> XC_PAGE_SHIFT) + offset + i;
+        gpfns[i]= (sshm->begin >> XC_PAGE_SHIFT) + i;
+    }
+    rc = xc_domain_add_to_physmap_batch(CTX->xch,
+                                        sid, mid,
+                                        XENMAPSPACE_gmfn_foreign,
+                                        num_spages,
+                                        idxs, gpfns, errs);
+
+    num_success = 0;
+    for (i = 0; i < num_spages; i++) {
+        if (errs[i]) {
+            SSHM_ERROR(sid, sshm->id,
+                       "can't map at address 0x%"PRIx64".",
+                       gpfns[i] << XC_PAGE_SHIFT);
+            rc = ERROR_FAIL;
+        } else {
+            mapped[num_success++] = gpfns[i];
+        }
+    }
+    *nmapped = num_success;
+    if (rc) goto out;
+
+    rc = 0;
+out:
+    return rc;
+}
+
+static int libxl__sshm_incref(libxl__gc *gc, xs_transaction_t xt,
+                              const char *sshm_path)
+{
+    int rc, count;
+    const char *count_path, *count_string;
+
+    count_path = GCSPRINTF("%s/users", sshm_path);
+    rc = libxl__xs_read_checked(gc, xt, count_path, &count_string);
+    if (rc) goto out;
+    count = atoi(count_string);
+
+    count_string = GCSPRINTF("%d", count+1);
+    rc = libxl__xs_write_checked(gc, xt, count_path, count_string);
+    if (rc) goto out;
+
+    rc = 0;
+out:
+    return rc;
+}
+

[...]

Quoted 21 lines
tools/libxl/Makefile +21 -0
+
+        /* all checks passed, do the job */
+        if (!isretry) {
+            rc = libxl__sshm_do_map(gc, master_domid, domid,
+                                    sshm, &master_sshm,
+                                    mapped, &nmapped);
+            if (rc) goto out;
+        }
+
+        /* write the result to xenstore and commit */
+        rc = libxl__xs_write_checked(gc, xt, dom_role_path, "slave");
+        if (rc) goto out;
+        rc = libxl__xs_writev(gc, xt, slave_path, ents);
+        if (rc) goto out;
+        rc = libxl__sshm_incref(gc, xt, sshm_path);
+        if (rc) goto out;
+
+        rc = libxl__xs_transaction_commit(gc, &xt);
+        if (!rc) break;
+        if (rc < 0) goto out;
+        isretry = true;

tools/libxl/Makefile

Quoted 10 lines
tools/libxl/Makefile +10 -0
+    }
+
+    rc = 0;
+out:
+    if (rc) {
+        /* role back successfully mapped pages */
+        SSHM_ERROR(domid, sshm->id, "failed to map some pages, cancelling.");
+        for (i = 0; i < nmapped; i++) {
+            xc_domain_remove_from_physmap(CTX->xch, domid, mapped[i]);
+        }

It is possible to get here when the first attempt of mapping has failed. The do_map function can return early before it modifies nmapped. At first glance this code snippet is buggy.

Quoted 2 lines

I would suggest you change isretry to mapped and adjust the predicate for rolling back.

nmapped was initialized to 0, so even if do_map fails early (and the only possible case
where do_map doesn't modify nmapped is when no page was actually mapped), the value of nmapped stay correct and no pages will be rolled back.

Quoted 47 lines
Quoted 33 lines
tools/libxl/Makefile +32 -0
+    }
+
+    libxl__xs_transaction_abort(gc, &xt);
+
+    return rc;
+}
+
+static int libxl__sshm_add_master(libxl__gc *gc, uint32_t domid,
+                                  libxl_static_shm *sshm)
+{
+    int rc;
+    const char *sshm_path, *dom_path, *dom_role_path;
+    char *ents[13];
+    struct xs_permissions noperm;
+    xs_transaction_t xt = XBT_NULL;
+
+    sshm_path = SSHM_PATH(sshm->id);
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    /* the domain should be in xenstore by now */
+    assert(dom_path);
+    dom_role_path = GCSPRINTF("%s/static_shm/%s/role", dom_path, sshm->id);
+
+    /* prepare the xenstore entries */
+    ents[0] = "master";
+    ents[1] = GCSPRINTF("%"PRIu32, domid);
+    ents[2] = "begin";
+    ents[3] = GCSPRINTF("0x%"PRIx64, sshm->begin);
+    ents[4] = "end";
+    ents[5] = GCSPRINTF("0x%"PRIx64, sshm->end);
+    ents[6] = "prot";
+    ents[7] = libxl__strdup(gc, libxl_sshm_prot_to_string(sshm->prot));
+    ents[8] = "cache_policy";

tools/libxl/Makefile

Quoted 10 lines
tools/libxl/Makefile +10 -0
+    ents[9] = libxl__strdup(gc,
+                            libxl_sshm_cachepolicy_to_string(sshm->cache_policy));
+    ents[10] = "users";
+    ents[11] = "1";
+    ents[12] = NULL;
+
+    /* could only be accessed by Dom0 */
+    noperm.id = 0;
+    noperm.perms = XS_PERM_NONE;
+

The owner of the path is going to be Dom0 and all other domains have no permission, which matches the comment.

Quoted 3 lines

Do you not want domid to be able to read? If you don't want it to read from the path, why not put in under some other paths like /libxl/?

I think this is to be discussed. But in my opinion, the target user won't need this information because the address is often statically setup and hardcoded in the simple bare metal apps running inside the DomU's, so I will currently mark it as noperm and move it to /libxl as you suggested (secure by default). If, the future, there are needs to read this information from within the DomU's, we could easily move it back and set the permissions accordingly.

Quoted 62 lines
Quoted 34 lines
tools/libxl/Makefile +34 -0
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &xt);
+        if (rc) goto out;
+
+        if (!libxl__xs_read(gc, xt, sshm_path)) {
+            /* every ID can appear in each domain at most once */
+            if (libxl__xs_read(gc, xt, dom_role_path)) {
+                SSHM_ERROR(domid, sshm->id,
+                           "domain tried to map the same ID twice.");
+                rc = ERROR_FAIL;
+                goto out;
+            }
+            rc = libxl__xs_write_checked(gc, xt, dom_role_path, "master");
+            if (rc) goto out;;
+
+            libxl__xs_mknod(gc, xt, sshm_path, &noperm, 1);
+            libxl__xs_writev(gc, xt, sshm_path, ents);
+        } else {
+            SSHM_ERROR(domid, sshm->id, "can only have one master.");
+            rc = ERROR_FAIL;
+            goto out;
+        }
+
+        rc = libxl__xs_transaction_commit(gc, &xt);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    rc = 0;
+out:
+    libxl__xs_transaction_abort(gc, &xt);
+    return rc;
+}
+

[...]

tools/libxl/libxl_x86.c void libxl__arch_domain_build_info_acpi_setdefault( · line 603

Quoted 13 lines
tools/libxl/libxl_x86.c +5 -0
index 5f91fe4f92..450fb3d354 100644
@@ -596,6 +596,24 @@ void libxl__arch_domain_build_info_acpi_setdefault(
     libxl_defbool_setdefault(&b_info->acpi, true);
 }
 
+bool libxl__arch_domain_support_sshm(const libxl_domain_build_info *b_info)
+{
+    /* FIXME: Mark this as unsupported for calling p2m_add_foreign on two
+     * DomU's is currently not allowd on x86, see the comments in
+     * x86/mm/p2m.c: p2m_add_foreign */

Move the */ to a new line please. And add "." after "p2m_add_foreign".

Quoted 11 lines
tools/libxl/libxl_x86.c +11 -0
+     return false;
+}
+
+int libxl__arch_domain_sshm_cachepolicy_setdefault(libxl_static_shm *sshm)
+{
+    if (sshm->cache_policy == LIBXL_SSHM_CACHEPOLICY_UNKNOWN)
+        sshm->cache_policy = LIBXL_SSHM_CACHEPOLICY_X86_NORMAL;
+    if (sshm->cache_policy < LIBXL_SSHM_CACHEPOLICY_X86_NORMAL)
+        return ERROR_INVAL;
+
+    return 0;
Quoted 8 lines
Quoted 8 lines
tools/libxl/libxl_x86.c +2 -1
+}
+
 /*
  * Local variables:
  * mode: C
--

2.14.2

Cheers,

Zhongze Liu

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#23 lore raw

PATCH v3 5/7 libxl: support unmapping static shared memory areas during domain destruction

In reply to Zhongze Liu

Add libxl__sshm_del to unmap static shared memory areas mapped by libxl__sshm_add during domain creation. The unmapping process is:

* For a master: decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.
* For a slave: unmap the shared pages, and cleanup related xs entries. decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>
---
 tools/libxl/libxl_domain.c   |   5 +++
 tools/libxl/libxl_internal.h |   2 +
 tools/libxl/libxl_sshm.c     | 105 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+)
tools/libxl/libxl_domain.c +5 -0
index 814f8128a1..ce90387173 100644
@@ -1026,6 +1026,11 @@ void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
         goto out;
     }
 
+    rc = libxl__sshm_del(gc, domid);
+    if (rc) {
+        LOGD(ERROR, domid, "Deleting static shm failed.");
+    }
+
     if (libxl__device_pci_destroy_all(gc, domid) < 0)
         LOGD(ERROR, domid, "Pci shutdown failed");
     rc = xc_domain_pause(ctx->xch, domid);
tools/libxl/libxl_internal.h +2 -0
index fc28191625..dc5937e712 100644
@@ -4358,6 +4358,8 @@ static inline bool libxl__string_is_default(char **s)
 _hidden int libxl__sshm_add(libxl__gc *gc, uint32_t domid,
                             libxl_static_shm *sshm, int len);
 
+_hidden int libxl__sshm_del(libxl__gc *gc, uint32_t domid);
+
 _hidden int libxl__sshm_check_overlap(libxl__gc *gc, uint32_t domid,
                                       libxl_static_shm *sshms, int len);
 _hidden int libxl__sshm_setdefault(libxl__gc *gc, uint32_t domid,
tools/libxl/libxl_sshm.c +105 -0

111 lines not on this page · raw message

Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
#24 lore raw

Re: [PATCH v3 5/7] libxl: support unmapping static shared memory areas during domain destruction

Quoted 9 lines · Zhongze Liu

Add libxl__sshm_del to unmap static shared memory areas mapped by libxl__sshm_add during domain creation. The unmapping process is:

* For a master: decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.
* For a slave: unmap the shared pages, and cleanup related xs entries. decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.

This appears to be in line with what we discussed.

I would like to see some explanation for: if one or more of the things the code does fail half way, the system is still going to be in a consistent state. Most notably, there isn't going to be any page leaked with uncleaned refs.

tools/libxl/libxl_sshm.c int libxl__sshm_check_overlap(libxl__gc *gc, uint32_t domid, · line 185

Quoted 5 lines
tools/libxl/libxl_sshm.c +5 -0
+
+        rc = libxl__xs_transaction_commit(gc, &xt);
+        if (!rc) break;
+        if (rc < 0) goto out;
+         isretry = true;

Indentation.

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#25 lore raw

Re: [PATCH v3 5/7] libxl: support unmapping static shared memory areas during domain destruction

Hi Wei,

2017-11-01 23:55 GMT+08:00 Wei Liu <[email protected]>:

Quoted 11 lines · Zhongze Liu
Quoted 9 lines

Add libxl__sshm_del to unmap static shared memory areas mapped by libxl__sshm_add during domain creation. The unmapping process is:

* For a master: decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.
* For a slave: unmap the shared pages, and cleanup related xs entries. decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.

Quoted 7 lines

This appears to be in line with what we discussed.

I would like to see some explanation for: if one or more of the things the code does fail half way, the system is still going to be in a consistent state. Most notably, there isn't going to be any page leaked with uncleaned refs.

The unmapping code is invoked during the domain destruction process, so we can't roll back. Everything done here is a "best effort": even if the code fails half way, what I could do is to report the errors and proceed anyway.

I might be totally wrong. So please correct me.

Quoted 7 lines

tools/libxl/libxl_sshm.c int libxl__sshm_check_overlap(libxl__gc *gc, uint32_t domid, · line 185

Quoted 5 lines
tools/libxl/libxl_sshm.c +5 -0
+
+        rc = libxl__xs_transaction_commit(gc, &xt);
+        if (!rc) break;
+        if (rc < 0) goto out;
+         isretry = true;

Indentation.

Cheers,

Zhongze Liu

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#26 lore raw

Re: [PATCH v3 5/7] libxl: support unmapping static shared memory areas during domain destruction

Oops, The address lines were somehow dropped by my mail client. Adding Wei.

2017-11-09 10:06 GMT+08:00 Zhongze Liu <[email protected]>:

Quoted 34 lines

Hi Wei,

2017-11-01 23:55 GMT+08:00 Wei Liu <[email protected]>:

Quoted 11 lines · Zhongze Liu
Quoted 9 lines

Add libxl__sshm_del to unmap static shared memory areas mapped by libxl__sshm_add during domain creation. The unmapping process is:

* For a master: decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.
* For a slave: unmap the shared pages, and cleanup related xs entries. decrease the refcount of the sshm region, if the refcount reaches 0, cleanup the whole sshm path.

Quoted 7 lines

This appears to be in line with what we discussed.

I would like to see some explanation for: if one or more of the things the code does fail half way, the system is still going to be in a consistent state. Most notably, there isn't going to be any page leaked with uncleaned refs.

The unmapping code is invoked during the domain destruction process, so we can't roll back. Everything done here is a "best effort": even if the code fails half way, what I could do is to report the errors and proceed anyway.

I might be totally wrong. So please correct me.

Quoted 6 lines
Quoted 5 lines
tools/libxl/libxl_sshm.c +5 -0
+
+        rc = libxl__xs_transaction_commit(gc, &xt);
+        if (!rc) break;
+        if (rc < 0) goto out;
+         isretry = true;
Quoted 5 lines
Quoted 1 line

Indentation.

Cheers,

Zhongze Liu

_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel

#27 lore raw

PATCH v3 6/7 libxl:xl: add parsing code to parse "libxl_static_sshm" from xl config files

In reply to Zhongze Liu

Add the parsing utils for the newly introduced libxl_static_sshm struct to the libxl/libxlu_* family. And add realated parsing code in xl to parse the struct from xl config files. This is for the proposal "Allow setting up shared memory areas between VMs from xl config file" (see [1]).

[1] https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Wei Liu <[email protected]>
Cc Ian Jackson <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>
---
 tools/libxl/Makefile      |   2 +-
 tools/libxl/libxlu_sshm.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxlutil.h   |   6 ++
 tools/xl/xl_parse.c       |  24 +++++-
 4 files changed, 240 insertions(+), 2 deletions(-)
 create mode 100644 tools/libxl/libxlu_sshm.c
tools/libxl/Makefile +1 -1
index 91bc70cda2..25e6f0bd7f 100644
@@ -176,7 +176,7 @@ AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h _libxl_list.h _paths.h \
 AUTOSRCS= libxlu_cfg_y.c libxlu_cfg_l.c
 AUTOSRCS += _libxl_save_msgs_callout.c _libxl_save_msgs_helper.c
 LIBXLU_OBJS = libxlu_cfg_y.o libxlu_cfg_l.o libxlu_cfg.o \
-	libxlu_disk_l.o libxlu_disk.o libxlu_vif.o libxlu_pci.o
+	libxlu_disk_l.o libxlu_disk.o libxlu_vif.o libxlu_pci.o libxlu_sshm.o
 $(LIBXLU_OBJS): CFLAGS += $(CFLAGS_libxenctrl) # For xentoollog.h
 
 $(TEST_PROG_OBJS) _libxl.api-for-check: CFLAGS += $(CFLAGS_libxentoollog) $(CFLAGS_libxentoolcore)
tools/libxl/libxlu_sshm.c new file +210 -0

210 lines not on this page · raw message

tools/libxl/libxlutil.h +6 -0
index e81b644c01..ee39cb5bdc 100644
@@ -118,6 +118,12 @@ int xlu_rdm_parse(XLU_Config *cfg, libxl_rdm_reserve *rdm, const char *str);
 int xlu_vif_parse_rate(XLU_Config *cfg, const char *rate,
                        libxl_device_nic *nic);
 
+/*
+ * static shared memory specification parsing
+ */
+int xlu_sshm_parse(XLU_Config *cfg, const char *spec,
+                   libxl_static_shm *sshm);
+
 #endif /* LIBXLUTIL_H */
 
 /*
tools/xl/xl_parse.c +23 -1
index 9a692d5ae6..bf425f0ff3 100644
@@ -860,7 +860,7 @@ void parse_config_data(const char *config_source,
     long l, vcpus = 0;
     XLU_Config *config;
     XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
-                   *usbctrls, *usbdevs, *p9devs, *vdispls;
+                   *usbctrls, *usbdevs, *p9devs, *vdispls, *sshms;
     XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs,
                    *mca_caps;
     int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian, num_mca_caps;
@@ -1555,6 +1555,28 @@ void parse_config_data(const char *config_source,
         }
     }
 
+    if (!xlu_cfg_get_list (config, "static_shm", &sshms, 0, 0)) {
+        d_config->num_sshms = 0;
+        d_config->sshms = NULL;
+        while ((buf = xlu_cfg_get_listitem (sshms, d_config->num_sshms)) != NULL) {
+            libxl_static_shm *sshm;
+            char *buf2 = strdup(buf);
+            int ret;
+
+            sshm = ARRAY_EXTEND_INIT_NODEVID(d_config->sshms,
+                                             d_config->num_sshms,
+                                             libxl_static_shm_init);
+            ret = xlu_sshm_parse(config, buf2, sshm);
+            if (ret) {
+                fprintf(stderr,
+                        "xl: Invalid argument for static_shm: %s", buf2);
+                exit(EXIT_FAILURE);
+            }
+
+            free(buf2);
+        }
+    }
+
     if (!xlu_cfg_get_list(config, "p9", &p9devs, 0, 0)) {
         libxl_device_p9 *p9;
         char *security_model = NULL;
Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
#28 lore raw

PATCH v3 7/7 docs: documentation about static shared memory regions

In reply to Zhongze Liu

Add docs to document the motivation, usage, use cases and other relavant infomation about the static shared memory feature.

This is for the proposal "Allow setting up shared memory areas between VMs from xl config file". See:

https://lists.xen.org/archives/html/xen-devel/2017-08/msg03242.html

Cc Ian Jackson <[email protected]>
Cc Wei Liu <[email protected]>
Cc Stefano Stabellini <[email protected]>
Cc Julien Grall <[email protected]>
---
 docs/man/xl-static-shm-configuration.pod.5 | 257 +++++++++++++++++++++++++++++
 docs/man/xl.cfg.pod.5.in                   |   8 +
 docs/misc/xenstore-paths.markdown          |  47 ++++++
 3 files changed, 312 insertions(+)
 create mode 100644 docs/man/xl-static-shm-configuration.pod.5
docs/man/xl-static-shm-configuration.pod.5 new file +257 -0
new file mode 100644
index 0000000000..f103499a87
@@ -0,0 +1,257 @@
+=head1 NAME
+
+xl-static-shm-configuration - XL Static Shared Memeory Configuration Syntax
+
+
+(B<NOTE>: This is currently only available to ARM guests.)
+
+=head1 DESCRIPTION
+
+The static_shm option allows users to statically setup shared memory regions
+among a group of VMs, enabling guests without grant table support to do
+shm-based communication.
+
+Every shared region is:
+
+=over 4
+
+* Uniquely identified by a string that is no longer than 128 characters, which
+is called an B<identifier> in this document.
+
+* Backed by exactely one domain, which is called a B<master> domain, and all
+the other domains who are also sharing this region are called B<slave>s.
+
+=back
+
+=head1 SYNTAX
+
+This document specifies syntax of the static shared memory configuration in
+the xl config file. It has the following form:
+
+    static_shm = [ "SSHM_SPEC", "SSHM_SPEC", ... ]
+
+where each C<SSHM_SPEC> is in this form:
+
+    [<key>=<value>,]*
+
+Valid examples of C<SSHM_SPEC> are:
+
+    id=ID1, begin=0x100000, end=0x200000, role=master, cache_policy=x86_normal
+    id=ID1, offset = 0, begin=0x500000, end=0x600000, role=slave, prot=rw
+    id=ID2, begin=0x300000, end=0x400000, role=master
+    id=ID2, offset = 0x10000, begin=0x690000, end=0x800000, role=slave
+    id=ID2, offset = 0x10000, begin=0x690000, end=0x800000, role=slave
+
+These might be specified in the domain config file like this:
+
+    static_shm = ["id=ID2, offset = 0x10000, begin=0x690000, end=0x800000,
+role=slave"]
+
+
+More formally, the string is a series of comma-separated keyword/value
+pairs. Each parameter may be specified at most once. Default values apply if
+the parameter is not specified.
+
+=head1 Parameters
+
+=over 4
+
+=item B<id>
+
+=over 4
+
+=item Description
+
+The unique identifier of the shared memory region.
+
+Every identifier could appear only once in each xl config file.
+
+=item Supported values
+
+A string that contains alphanumerics and "_"s, and is no longer than 128
+characters.
+
+=item Default value
+
+None, this parameter is mandatory.
+
+=back
+
+=item B<begin>/B<end>
+
+=over 4
+
+=item Description
+
+The boundaries of the shared memory area.
+
+=item Supported values
+
+Same with B<offset>.
+
+=item Default Value
+
+None, this parameter is mandatory.
+
+=back
+
+=item B<offset>
+
+=over 4
+
+=item Description
+
+Can only appear when B<role> = slave. If set, the address mapping will not
+start from the beginning the backing memory region, but from the middle
+(B<offet> bytes away from the beginning) of it. See the graph below:
+
+With B<offset> = 0, the mapping will look like:
+
+  backing memory region:  #########################################
+                          |                       |
+                          |                       |
+                          |                       |
+                          V                       V
+  slave's shared region:  #########################
+
+With B<offset> > 0:
+
+  backing memory region:   #########################################
+                           |<-- offset -->||                       |
+                                           |                       |
+                                           |                       |
+                                           V                       V
+  slave's memory region:                   #########################
+
+=item Supported values
+
+Decimals or hexadecimals with an optional prefix "0x", and should be the
+multiple of the hypervisor page granularity (currently 4K on both ARM and x86).
+
+=item Default value
+
+0x0
+
+=back
+
+=item B<role>
+
+=over 4
+
+=item Description
+
+The backing area would be taken from one domain, which we will mark
+as the "master domain", and this domain should be created prior to any
+other slave domains that depend on it.
+
+This arugment specifies the role of this domain.
+
+=item Supported values
+
+master, slave
+
+=item Default value
+
+slave
+
+=back
+
+=item B<prot>
+
+=over 4
+
+=item Description
+
+When B<role> = master, this means the largest set of stage-2 permission flags
+that can be granted to the slave domains. When B<role> = slave, this means the
+stage-2 permission flags of the shared memory area.
+
+=item Supported values
+
+Currently only 'rw' is supported.
+
+=item Default value
+
+rw
+
+=back
+
+=item B<cache_policy>
+
+=over 4
+
+=item Description
+
+The stage-2 cacheability/shareability attributes of the shared memory area.
+This can only appear when B<role> = master.
+
+=item Supported values
+
+Currently, only the following policy is supported:
+
+=over 4
+
+=item B<ARM_normal>
+
+Only applicable to ARM guests. This would mean Inner and Outer Write-Back
+Cacheable, and Inner Shareable.
+
+=back
+
+=item Default value
+
+ARM_normal
+
+=back
+
+=back
+
+=head1 TYPICAL USAGE
+
+A typical procedure of setting up a shared mem region among several VMs is:
+
+=over 4
+
+1. Add a static_shm option to the master domain's xl config file, assign an
+B<ID> to it and mark it's B<role> as master, and set up the boundaries, prot
+flag, and B<cache_policy> appropriately.
+
+2. Add a static_shm option to every slave domain's xl config file, set
+their B<ID> to the same value as the master's, and set up the B<offset>,
+boundaries and prot flag appropriately.
+
+3. Create the master domain.
+
+4. Create the slaves.
+
+=back
+
+Remember that the master domain must be created before any slave domains could
+be created, for the slaves depend on the memory pages backed by their master.
+
+=head1 Example
+
+Suppose that we have 3 domains: vm1~vm3. And we want to setup two shared
+regions, say, ID1 and ID2, among the three domains, with the following address
+mapping:
+
+   ID1: (vm1 : 0x100000~0x200000) <=====> (vm2 : 0x500000~0x600000)
+   ID2: (vm1 : 0x310000~0x400000) <=====> (vm3 : 0x690000~0x800000)
+
+According to the syntax defined above, the xl config files of the three domains
+should contains the following content:
+
+In xl config file of vm1:
+  static_shm = [ "id=ID1, begin=0x100000, end=0x200000, role=master,
+cache_policy=x86_normal, prot=rw",
+"id=ID2, begin=0x300000, end=0x400000, role=master" ]
+
+In xl config file of vm2:
+  static_shm = [ "id=ID1, offset=0, begin=0x500000, end=0x600000,
+role=slave, prot=rw" ]
+
+In xl config file of vm3:
+  static_shm = [ "id=ID2, offset=0x10000, begin=0x690000,
+end=0x800000, role=slave" ]
+
+After that, just create vm1 first, and then create vm2 and vm3 in any order.
docs/man/xl.cfg.pod.5.in +8 -0
index b7b91d8627..21540ba15a 100644
@@ -277,6 +277,14 @@ memory=8096 will report significantly less memory available for use
 than a system with maxmem=8096 memory=8096 due to the memory overhead
 of having to track the unused pages.
 
+=item B<static_shm=[ "SSHM_SPEC", "SSHM_SPEC", ... ]>
+
+Specifies the static shared memory regions of this guest. Static shared
+memory regions enables guests to communicate with each other through
+one or more shared memory regions, even without grant table support.
+Currently, this only works on ARM guests.
+See L<xl-static-shm-configuration(5)> for more details.
+
 =back
 
 =head3 Guest Virtual NUMA Configuration
docs/misc/xenstore-paths.markdown +47 -0

59 lines not on this page · raw message

Signature · 7 lines
2.14.2


_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel