[PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target

Jason Andryuk posted 17 patches 3 months, 2 weeks ago
[PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Jason Andryuk 3 months, 2 weeks ago
Add a new create domain flag  to indicate if a domain can be the target
of hypercalls.  By default all domains can be targetted - subject to any
other permission checks.

This property is useful in a safety environment to isolate domains for
freedom from interference.

Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
---
DOMAIN_CAPS_NOT_HYPERCALL_TARGET duplicates the hypercall-untargetable
DT property, so it could be removed.  Leaving it here for now to at
least illustrate the alternate approach.
---
 docs/misc/arm/device-tree/booting.txt   |  6 ++++++
 tools/ocaml/libs/xc/xenctrl.ml          |  1 +
 tools/ocaml/libs/xc/xenctrl.mli         |  1 +
 xen/arch/arm/domain.c                   |  3 ++-
 xen/common/device-tree/dom0less-build.c |  6 ++++++
 xen/common/domain.c                     |  2 +-
 xen/include/public/bootfdt.h            | 10 ++++++++--
 xen/include/public/domctl.h             |  4 +++-
 xen/include/xen/sched.h                 | 12 ++++++++++++
 xen/include/xsm/dummy.h                 |  4 ++++
 10 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt
index 07acc7ba64..963dd81912 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -307,6 +307,12 @@ with the following properties:
     passed through. This option is the default if this property is missing
     and the user does not provide the device partial device tree for the domain.
 
+- hypercall-untargetable
+
+    Optional.  An empty property to specify the domain cannot be the target
+    of hypercalls.  This protects a domain for freedom of interference from
+    other domains.
+
 Under the "xen,domain" compatible node, one or more sub-nodes are present
 for the DomU kernel and ramdisk.
 
diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml
index f5835e7d95..00c29199dc 100644
--- a/tools/ocaml/libs/xc/xenctrl.ml
+++ b/tools/ocaml/libs/xc/xenctrl.ml
@@ -72,6 +72,7 @@ type domain_create_flag =
   | CDF_VPMU
   | CDF_TRAP_UNMAPPED_ACCESSES
   | CDF_DEVICE_MODEL
+  | CDF_NOT_HYPERCALL_TARGET
 
 type domain_create_iommu_opts =
   | IOMMU_NO_SHAREPT
diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli
index b9471a56a8..daf6686f4d 100644
--- a/tools/ocaml/libs/xc/xenctrl.mli
+++ b/tools/ocaml/libs/xc/xenctrl.mli
@@ -65,6 +65,7 @@ type domain_create_flag =
   | CDF_VPMU
   | CDF_TRAP_UNMAPPED_ACCESSES
   | CDF_DEVICE_MODEL
+  | CDF_NOT_HYPERCALL_TARGET
 
 type domain_create_iommu_opts =
   | IOMMU_NO_SHAREPT
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 57eecbd250..5f6358096f 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -614,7 +614,8 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
     unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu |
                                    XEN_DOMCTL_CDF_xs_domain |
                                    XEN_DOMCTL_CDF_trap_unmapped_accesses |
-                                   XEN_DOMCTL_CDF_device_model);
+                                   XEN_DOMCTL_CDF_device_model |
+                                   XEN_DOMCTL_CDF_not_hypercall_target);
     unsigned int sve_vl_bits = sve_decode_vl(config->arch.sve_vl);
 
     if ( (config->flags & ~flags_optional) != flags_required )
diff --git a/xen/common/device-tree/dom0less-build.c b/xen/common/device-tree/dom0less-build.c
index bb52291dfb..22af043aa5 100644
--- a/xen/common/device-tree/dom0less-build.c
+++ b/xen/common/device-tree/dom0less-build.c
@@ -886,6 +886,9 @@ void __init create_domUs(void)
 
             if ( val & DOMAIN_CAPS_DEVICE_MODEL )
                 d_cfg.flags |= XEN_DOMCTL_CDF_device_model;
+
+            if ( val & DOMAIN_CAPS_NOT_HYPERCALL_TARGET )
+                d_cfg.flags |= XEN_DOMCTL_CDF_not_hypercall_target;
         }
 
         if ( dt_find_property(node, "xen,static-mem", NULL) )
@@ -896,6 +899,9 @@ void __init create_domUs(void)
             flags |= CDF_staticmem;
         }
 
+        if ( dt_property_read_bool(node, "hypercall-untargetable") )
+            d_cfg.flags |= XEN_DOMCTL_CDF_not_hypercall_target;
+
         if ( dt_property_read_bool(node, "direct-map") )
         {
             if ( !(flags & CDF_staticmem) )
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 42c590b8d7..c347de4335 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -723,7 +723,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
            XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
            XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu |
            XEN_DOMCTL_CDF_trap_unmapped_accesses |
-           XEN_DOMCTL_CDF_device_model) )
+           XEN_DOMCTL_CDF_device_model | XEN_DOMCTL_CDF_not_hypercall_target) )
     {
         dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
         return -EINVAL;
diff --git a/xen/include/public/bootfdt.h b/xen/include/public/bootfdt.h
index c6b5afc76a..1eba1cc487 100644
--- a/xen/include/public/bootfdt.h
+++ b/xen/include/public/bootfdt.h
@@ -32,8 +32,14 @@
  * Hardware domain for running QEMU.
  */
 #define DOMAIN_CAPS_DEVICE_MODEL (1U << 3)
+/*
+ * Domain cannot be the target of hypercalls.  This provides the domain
+ * freedom from interference from other domains.
+ */
+#define DOMAIN_CAPS_NOT_HYPERCALL_TARGET (1U << 4)
 
-#define DOMAIN_CAPS_MASK     (DOMAIN_CAPS_CONTROL  | DOMAIN_CAPS_HARDWARE | \
-                              DOMAIN_CAPS_XENSTORE | DOMAIN_CAPS_DEVICE_MODEL )
+#define DOMAIN_CAPS_MASK    (DOMAIN_CAPS_CONTROL  | DOMAIN_CAPS_HARDWARE | \
+                             DOMAIN_CAPS_XENSTORE | DOMAIN_CAPS_DEVICE_MODEL | \
+                             DOMAIN_CAPS_NOT_HYPERCALL_TARGET)
 
 #endif /* __XEN_PUBLIC_BOOTFDT_H__ */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 88a294c5be..f1f6f96bc2 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -70,9 +70,11 @@ struct xen_domctl_createdomain {
 #define XEN_DOMCTL_CDF_trap_unmapped_accesses  (1U << 8)
 /* Allow domain to provide device model for multiple other domains */
 #define XEN_DOMCTL_CDF_device_model   (1U << 9)
+/* Domain cannot be the target of hypercalls */
+#define XEN_DOMCTL_CDF_not_hypercall_target   (1U << 10)
 
 /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
-#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_device_model
+#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_not_hypercall_target
 
     uint32_t flags;
 
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 9863603d93..8a32f9a1b6 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -1157,6 +1157,18 @@ static always_inline bool is_dm_domain(const struct domain *d)
     return evaluate_nospec(d->options & XEN_DOMCTL_CDF_device_model);
 }
 
+/*
+ * Return whether this domain can be the target of hypercalls from other
+ * domains.
+ */
+static always_inline bool is_hypercall_target(const struct domain *d)
+{
+    if ( IS_ENABLED(CONFIG_PV_SHIM_EXCLUSIVE) )
+        return true;
+
+    return evaluate_nospec(!(d->options & XEN_DOMCTL_CDF_not_hypercall_target));
+}
+
 #define VM_ASSIST(d, t) (test_bit(VMASST_TYPE_ ## t, &(d)->vm_assist))
 
 static always_inline bool is_pv_domain(const struct domain *d)
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index 0b341efd18..f2205575ed 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -91,12 +91,16 @@ static always_inline int xsm_default_action(
             return 0;
         fallthrough;
     case XSM_DM_PRIV:
+        if ( target && !is_hypercall_target(target) )
+            return -EPERM;
         if ( is_dm_domain(src) )
             return 0;
         if ( target && evaluate_nospec(src->target == target) )
             return 0;
         fallthrough;
     case XSM_PRIV:
+        if ( target && !is_hypercall_target(target) )
+            return -EPERM;
         if ( is_control_domain(src) )
             return 0;
         return -EPERM;
-- 
2.50.0
Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Jan Beulich 3 months ago
On 16.07.2025 23:14, Jason Andryuk wrote:
> Add a new create domain flag  to indicate if a domain can be the target
> of hypercalls.  By default all domains can be targetted - subject to any
> other permission checks.

I think terminology needs clarifying here: What exactly does "targeted"
mean? Is that e.g. also intended to cover
XENMEM_{current,maximum}_reservation, which "target" a particular domain,
when at the same time they don't interfere with the targeted domain in
any way?

> --- a/xen/include/xsm/dummy.h
> +++ b/xen/include/xsm/dummy.h
> @@ -91,12 +91,16 @@ static always_inline int xsm_default_action(
>              return 0;
>          fallthrough;
>      case XSM_DM_PRIV:
> +        if ( target && !is_hypercall_target(target) )
> +            return -EPERM;
>          if ( is_dm_domain(src) )
>              return 0;
>          if ( target && evaluate_nospec(src->target == target) )
>              return 0;
>          fallthrough;
>      case XSM_PRIV:
> +        if ( target && !is_hypercall_target(target) )
> +            return -EPERM;

Hmm, for TARGET, XS_PRIV, and DM_PRIV we're now doing the same check
twice.

Jan

>          if ( is_control_domain(src) )
>              return 0;
>          return -EPERM;
Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Jason Andryuk 3 months ago
On 2025-07-30 11:06, Jan Beulich wrote:
> On 16.07.2025 23:14, Jason Andryuk wrote:
>> Add a new create domain flag  to indicate if a domain can be the target
>> of hypercalls.  By default all domains can be targetted - subject to any
>> other permission checks.
> 
> I think terminology needs clarifying here: What exactly does "targeted"
> mean? Is that e.g. also intended to cover
> XENMEM_{current,maximum}_reservation, which "target" a particular domain,
> when at the same time they don't interfere with the targeted domain in
> any way?

Avoiding interference is the primary goal.  Those hypercalls definitely 
need to be blocked.  xsm_default_action() has limited information 
available, so we can't differentiate particular hypercalls.  Blocking 
extra non-interfering hypercalls is not a problem for us.

>> --- a/xen/include/xsm/dummy.h
>> +++ b/xen/include/xsm/dummy.h
>> @@ -91,12 +91,16 @@ static always_inline int xsm_default_action(
>>               return 0;
>>           fallthrough;
>>       case XSM_DM_PRIV:
>> +        if ( target && !is_hypercall_target(target) )
>> +            return -EPERM;
>>           if ( is_dm_domain(src) )
>>               return 0;
>>           if ( target && evaluate_nospec(src->target == target) )
>>               return 0;
>>           fallthrough;
>>       case XSM_PRIV:
>> +        if ( target && !is_hypercall_target(target) )
>> +            return -EPERM;
> 
> Hmm, for TARGET, XS_PRIV, and DM_PRIV we're now doing the same check
> twice.

The different cases need to be covered somehow.  I didn't see a good way 
to avoid the duplication.

Regards,
Jason
Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Jan Beulich 3 months ago
On 30.07.2025 23:30, Jason Andryuk wrote:
> On 2025-07-30 11:06, Jan Beulich wrote:
>> On 16.07.2025 23:14, Jason Andryuk wrote:
>>> Add a new create domain flag  to indicate if a domain can be the target
>>> of hypercalls.  By default all domains can be targetted - subject to any
>>> other permission checks.
>>
>> I think terminology needs clarifying here: What exactly does "targeted"
>> mean? Is that e.g. also intended to cover
>> XENMEM_{current,maximum}_reservation, which "target" a particular domain,
>> when at the same time they don't interfere with the targeted domain in
>> any way?
> 
> Avoiding interference is the primary goal.  Those hypercalls definitely 
> need to be blocked.  xsm_default_action() has limited information 
> available, so we can't differentiate particular hypercalls.  Blocking 
> extra non-interfering hypercalls is not a problem for us.

Except that later patches then "punch holes" into the fence pulled up here.
And over time we may learn that more holes are needed, or at least wanted.

>>> --- a/xen/include/xsm/dummy.h
>>> +++ b/xen/include/xsm/dummy.h
>>> @@ -91,12 +91,16 @@ static always_inline int xsm_default_action(
>>>               return 0;
>>>           fallthrough;
>>>       case XSM_DM_PRIV:
>>> +        if ( target && !is_hypercall_target(target) )
>>> +            return -EPERM;
>>>           if ( is_dm_domain(src) )
>>>               return 0;
>>>           if ( target && evaluate_nospec(src->target == target) )
>>>               return 0;
>>>           fallthrough;
>>>       case XSM_PRIV:
>>> +        if ( target && !is_hypercall_target(target) )
>>> +            return -EPERM;
>>
>> Hmm, for TARGET, XS_PRIV, and DM_PRIV we're now doing the same check
>> twice.
> 
> The different cases need to be covered somehow.  I didn't see a good way 
> to avoid the duplication.

Maybe this is the point where the fall-through wants (needs?) doing away with.

Jan
Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Julien Grall 3 months, 1 week ago
Hi Jason,

On 16/07/2025 22:14, Jason Andryuk wrote:
> Add a new create domain flag  to indicate if a domain can be the target
> of hypercalls.  By default all domains can be targetted - subject to any
> other permission checks.
> 
> This property is useful in a safety environment to isolate domains for
> freedom from interference.

I see the flag is exposed to the toolstack. However, I don't see how you 
can successfully create a VM if you are not allowed to call hypercalls 
(for instance to add some memory).

I think, at minimum, you would want to allow hypercalls while the domain 
is created. That said, I wonder if this setup would not be better to 
describe with XSM?


[...]

> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index 88a294c5be..f1f6f96bc2 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -70,9 +70,11 @@ struct xen_domctl_createdomain {
>   #define XEN_DOMCTL_CDF_trap_unmapped_accesses  (1U << 8)
>   /* Allow domain to provide device model for multiple other domains */
>   #define XEN_DOMCTL_CDF_device_model   (1U << 9)
> +/* Domain cannot be the target of hypercalls */
> +#define XEN_DOMCTL_CDF_not_hypercall_target   (1U << 10)
>   
>   /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
> -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_device_model
> +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_not_hypercall_target

I am not sure where to comment. But aren't both flags mutually exclusive?

> diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
> index 0b341efd18..f2205575ed 100644
> --- a/xen/include/xsm/dummy.h
> +++ b/xen/include/xsm/dummy.h
> @@ -91,12 +91,16 @@ static always_inline int xsm_default_action(
>               return 0;
>           fallthrough;
>       case XSM_DM_PRIV:
> +        if ( target && !is_hypercall_target(target) )
> +            return -EPERM;
>           if ( is_dm_domain(src) )
>               return 0;
>           if ( target && evaluate_nospec(src->target == target) )
>               return 0;
>           fallthrough;
>       case XSM_PRIV:
> +        if ( target && !is_hypercall_target(target) )
> +            return -EPERM;
>           if ( is_control_domain(src) )
>               return 0;
>           return -EPERM;

Cheers,

-- 
Julien Grall
Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Jason Andryuk 3 months, 1 week ago
Hi Julien,

Thanks for taking a look.

On 2025-07-21 13:58, Julien Grall wrote:
> Hi Jason,
> 
> On 16/07/2025 22:14, Jason Andryuk wrote:
>> Add a new create domain flag  to indicate if a domain can be the target
>> of hypercalls.  By default all domains can be targetted - subject to any
>> other permission checks.
>>
>> This property is useful in a safety environment to isolate domains for
>> freedom from interference.
> 
> I see the flag is exposed to the toolstack. However, I don't see how you 
> can successfully create a VM if you are not allowed to call hypercalls 
> (for instance to add some memory).

Yes, you are right.  With dom0less/Hyperlaunch, I'd not been considering 
the toolstack.

> I think, at minimum, you would want to allow hypercalls while the domain 
> is created. That said, I wonder if this setup would not be better to 
> describe with XSM?

Re-labeling with Flask would allow different permissions between 
building and running.  domain_unpause would need to be allowed, but that 
doesn't stop a domain.

At first glance, like you say, the untargetable property could be 
enabled when domain creation finishes.

> 
> [...]
> 
>> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
>> index 88a294c5be..f1f6f96bc2 100644
>> --- a/xen/include/public/domctl.h
>> +++ b/xen/include/public/domctl.h
>> @@ -70,9 +70,11 @@ struct xen_domctl_createdomain {
>>   #define XEN_DOMCTL_CDF_trap_unmapped_accesses  (1U << 8)
>>   /* Allow domain to provide device model for multiple other domains */
>>   #define XEN_DOMCTL_CDF_device_model   (1U << 9)
>> +/* Domain cannot be the target of hypercalls */
>> +#define XEN_DOMCTL_CDF_not_hypercall_target   (1U << 10)
>>   /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
>> -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_device_model
>> +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_not_hypercall_target
> 
> I am not sure where to comment. But aren't both flags mutually exclusive?

No, XEN_DOMCTL_CDF_device_model is *this* domain providing the device 
model to other domains:

+ * Device model capability allows the use of the dm_op hypercalls to 
provide
+ * the device model emulation (run QEMU) for other domains.  This is a
+ * subset of the Control capability which can be granted to the
+ * Hardware domain for running QEMU.

Whereas XEN_DOMCTL_CDF_not_hypercall_target removes targeting on *this* 
domain.  So the domain with XEN_DOMCTL_CDF_device_model cannot target 
the XEN_DOMCTL_CDF_not_hypercall_target domain.

Regards,
Jason

Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Julien Grall 3 months, 1 week ago
Hi Jason,

On 21/07/2025 23:00, Jason Andryuk wrote:
>>> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
>>> index 88a294c5be..f1f6f96bc2 100644
>>> --- a/xen/include/public/domctl.h
>>> +++ b/xen/include/public/domctl.h
>>> @@ -70,9 +70,11 @@ struct xen_domctl_createdomain {
>>>   #define XEN_DOMCTL_CDF_trap_unmapped_accesses  (1U << 8)
>>>   /* Allow domain to provide device model for multiple other domains */
>>>   #define XEN_DOMCTL_CDF_device_model   (1U << 9)
>>> +/* Domain cannot be the target of hypercalls */
>>> +#define XEN_DOMCTL_CDF_not_hypercall_target   (1U << 10)
>>>   /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
>>> -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_device_model
>>> +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_not_hypercall_target
>>
>> I am not sure where to comment. But aren't both flags mutually exclusive?
> 
> No, XEN_DOMCTL_CDF_device_model is *this* domain providing the device 
> model to other domains:
> 
> + * Device model capability allows the use of the dm_op hypercalls to 
> provide
> + * the device model emulation (run QEMU) for other domains.  This is a
> + * subset of the Control capability which can be granted to the
> + * Hardware domain for running QEMU.
> 
> Whereas XEN_DOMCTL_CDF_not_hypercall_target removes targeting on *this* 
> domain.  So the domain with XEN_DOMCTL_CDF_device_model cannot target 
> the XEN_DOMCTL_CDF_not_hypercall_target domain.

Thanks for the clarification. I misunderstood the goal of 
XEN_DOMCTL_CDF_device_model. That said, I think there is still a problem 
because with CDF_not_hypercall_target, you would not be able to have a 
device-emulator for that domain. Is this intended?

Cheers,

> 
> Regards,
> Jason

-- 
Julien Grall


Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Jason Andryuk 3 months, 1 week ago
On 2025-07-23 05:29, Julien Grall wrote:
> Hi Jason,
> 
> On 21/07/2025 23:00, Jason Andryuk wrote:
>>>> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
>>>> index 88a294c5be..f1f6f96bc2 100644
>>>> --- a/xen/include/public/domctl.h
>>>> +++ b/xen/include/public/domctl.h
>>>> @@ -70,9 +70,11 @@ struct xen_domctl_createdomain {
>>>>   #define XEN_DOMCTL_CDF_trap_unmapped_accesses  (1U << 8)
>>>>   /* Allow domain to provide device model for multiple other domains */
>>>>   #define XEN_DOMCTL_CDF_device_model   (1U << 9)
>>>> +/* Domain cannot be the target of hypercalls */
>>>> +#define XEN_DOMCTL_CDF_not_hypercall_target   (1U << 10)
>>>>   /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
>>>> -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_device_model
>>>> +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_not_hypercall_target
>>>
>>> I am not sure where to comment. But aren't both flags mutually 
>>> exclusive?
>>
>> No, XEN_DOMCTL_CDF_device_model is *this* domain providing the device 
>> model to other domains:
>>
>> + * Device model capability allows the use of the dm_op hypercalls to 
>> provide
>> + * the device model emulation (run QEMU) for other domains.  This is a
>> + * subset of the Control capability which can be granted to the
>> + * Hardware domain for running QEMU.
>>
>> Whereas XEN_DOMCTL_CDF_not_hypercall_target removes targeting on 
>> *this* domain.  So the domain with XEN_DOMCTL_CDF_device_model cannot 
>> target the XEN_DOMCTL_CDF_not_hypercall_target domain.
> 
> Thanks for the clarification. I misunderstood the goal of 
> XEN_DOMCTL_CDF_device_model. That said, I think there is still a problem 
> because with CDF_not_hypercall_target, you would not be able to have a 
> device-emulator for that domain. Is this intended?

Yes, it is intentional that CDF_not_hypercall_target prevents using a 
device model.  With out safety use-case, we want to be able to avoid 
interference for specific domains.

Regards,
Jason

Re: [PATCH v2 04/17] xen: Introduce XEN_DOMCTL_CDF_not_hypercall_target
Posted by Stefano Stabellini 3 months, 2 weeks ago
On Wed, 16 Jul 2025, Jason Andryuk wrote:
> Add a new create domain flag  to indicate if a domain can be the target
> of hypercalls.  By default all domains can be targetted - subject to any
> other permission checks.
> 
> This property is useful in a safety environment to isolate domains for
> freedom from interference.
> 
> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
> ---
> DOMAIN_CAPS_NOT_HYPERCALL_TARGET duplicates the hypercall-untargetable
> DT property, so it could be removed.  Leaving it here for now to at
> least illustrate the alternate approach.
> ---
>  docs/misc/arm/device-tree/booting.txt   |  6 ++++++
>  tools/ocaml/libs/xc/xenctrl.ml          |  1 +
>  tools/ocaml/libs/xc/xenctrl.mli         |  1 +
>  xen/arch/arm/domain.c                   |  3 ++-
>  xen/common/device-tree/dom0less-build.c |  6 ++++++
>  xen/common/domain.c                     |  2 +-
>  xen/include/public/bootfdt.h            | 10 ++++++++--
>  xen/include/public/domctl.h             |  4 +++-
>  xen/include/xen/sched.h                 | 12 ++++++++++++
>  xen/include/xsm/dummy.h                 |  4 ++++
>  10 files changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt
> index 07acc7ba64..963dd81912 100644
> --- a/docs/misc/arm/device-tree/booting.txt
> +++ b/docs/misc/arm/device-tree/booting.txt
> @@ -307,6 +307,12 @@ with the following properties:
>      passed through. This option is the default if this property is missing
>      and the user does not provide the device partial device tree for the domain.
>  
> +- hypercall-untargetable
> +
> +    Optional.  An empty property to specify the domain cannot be the target
> +    of hypercalls.  This protects a domain for freedom of interference from
> +    other domains.

This protects a domain from interference

or

This protects a domain ensuring freedom of interference from other
domains


>  Under the "xen,domain" compatible node, one or more sub-nodes are present
>  for the DomU kernel and ramdisk.
>  
> diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml
> index f5835e7d95..00c29199dc 100644
> --- a/tools/ocaml/libs/xc/xenctrl.ml
> +++ b/tools/ocaml/libs/xc/xenctrl.ml
> @@ -72,6 +72,7 @@ type domain_create_flag =
>    | CDF_VPMU
>    | CDF_TRAP_UNMAPPED_ACCESSES
>    | CDF_DEVICE_MODEL
> +  | CDF_NOT_HYPERCALL_TARGET
>  
>  type domain_create_iommu_opts =
>    | IOMMU_NO_SHAREPT
> diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli
> index b9471a56a8..daf6686f4d 100644
> --- a/tools/ocaml/libs/xc/xenctrl.mli
> +++ b/tools/ocaml/libs/xc/xenctrl.mli
> @@ -65,6 +65,7 @@ type domain_create_flag =
>    | CDF_VPMU
>    | CDF_TRAP_UNMAPPED_ACCESSES
>    | CDF_DEVICE_MODEL
> +  | CDF_NOT_HYPERCALL_TARGET
>  
>  type domain_create_iommu_opts =
>    | IOMMU_NO_SHAREPT
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 57eecbd250..5f6358096f 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -614,7 +614,8 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
>      unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu |
>                                     XEN_DOMCTL_CDF_xs_domain |
>                                     XEN_DOMCTL_CDF_trap_unmapped_accesses |
> -                                   XEN_DOMCTL_CDF_device_model);
> +                                   XEN_DOMCTL_CDF_device_model |
> +                                   XEN_DOMCTL_CDF_not_hypercall_target);
>      unsigned int sve_vl_bits = sve_decode_vl(config->arch.sve_vl);
>  
>      if ( (config->flags & ~flags_optional) != flags_required )
> diff --git a/xen/common/device-tree/dom0less-build.c b/xen/common/device-tree/dom0less-build.c
> index bb52291dfb..22af043aa5 100644
> --- a/xen/common/device-tree/dom0less-build.c
> +++ b/xen/common/device-tree/dom0less-build.c
> @@ -886,6 +886,9 @@ void __init create_domUs(void)
>  
>              if ( val & DOMAIN_CAPS_DEVICE_MODEL )
>                  d_cfg.flags |= XEN_DOMCTL_CDF_device_model;
> +
> +            if ( val & DOMAIN_CAPS_NOT_HYPERCALL_TARGET )
> +                d_cfg.flags |= XEN_DOMCTL_CDF_not_hypercall_target;
>          }
>  
>          if ( dt_find_property(node, "xen,static-mem", NULL) )
> @@ -896,6 +899,9 @@ void __init create_domUs(void)
>              flags |= CDF_staticmem;
>          }
>  
> +        if ( dt_property_read_bool(node, "hypercall-untargetable") )
> +            d_cfg.flags |= XEN_DOMCTL_CDF_not_hypercall_target;
> +
>          if ( dt_property_read_bool(node, "direct-map") )
>          {
>              if ( !(flags & CDF_staticmem) )
> diff --git a/xen/common/domain.c b/xen/common/domain.c
> index 42c590b8d7..c347de4335 100644
> --- a/xen/common/domain.c
> +++ b/xen/common/domain.c
> @@ -723,7 +723,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
>             XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
>             XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu |
>             XEN_DOMCTL_CDF_trap_unmapped_accesses |
> -           XEN_DOMCTL_CDF_device_model) )
> +           XEN_DOMCTL_CDF_device_model | XEN_DOMCTL_CDF_not_hypercall_target) )
>      {
>          dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
>          return -EINVAL;
> diff --git a/xen/include/public/bootfdt.h b/xen/include/public/bootfdt.h
> index c6b5afc76a..1eba1cc487 100644
> --- a/xen/include/public/bootfdt.h
> +++ b/xen/include/public/bootfdt.h
> @@ -32,8 +32,14 @@
>   * Hardware domain for running QEMU.
>   */
>  #define DOMAIN_CAPS_DEVICE_MODEL (1U << 3)
> +/*
> + * Domain cannot be the target of hypercalls.  This provides the domain
> + * freedom from interference from other domains.
> + */
> +#define DOMAIN_CAPS_NOT_HYPERCALL_TARGET (1U << 4)
>  
> -#define DOMAIN_CAPS_MASK     (DOMAIN_CAPS_CONTROL  | DOMAIN_CAPS_HARDWARE | \
> -                              DOMAIN_CAPS_XENSTORE | DOMAIN_CAPS_DEVICE_MODEL )
> +#define DOMAIN_CAPS_MASK    (DOMAIN_CAPS_CONTROL  | DOMAIN_CAPS_HARDWARE | \
> +                             DOMAIN_CAPS_XENSTORE | DOMAIN_CAPS_DEVICE_MODEL | \
> +                             DOMAIN_CAPS_NOT_HYPERCALL_TARGET)
>  
>  #endif /* __XEN_PUBLIC_BOOTFDT_H__ */
> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index 88a294c5be..f1f6f96bc2 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -70,9 +70,11 @@ struct xen_domctl_createdomain {
>  #define XEN_DOMCTL_CDF_trap_unmapped_accesses  (1U << 8)
>  /* Allow domain to provide device model for multiple other domains */
>  #define XEN_DOMCTL_CDF_device_model   (1U << 9)
> +/* Domain cannot be the target of hypercalls */
> +#define XEN_DOMCTL_CDF_not_hypercall_target   (1U << 10)
>  
>  /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
> -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_device_model
> +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_not_hypercall_target
>  
>      uint32_t flags;
>  
> diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
> index 9863603d93..8a32f9a1b6 100644
> --- a/xen/include/xen/sched.h
> +++ b/xen/include/xen/sched.h
> @@ -1157,6 +1157,18 @@ static always_inline bool is_dm_domain(const struct domain *d)
>      return evaluate_nospec(d->options & XEN_DOMCTL_CDF_device_model);
>  }
>  
> +/*
> + * Return whether this domain can be the target of hypercalls from other
> + * domains.
> + */
> +static always_inline bool is_hypercall_target(const struct domain *d)
> +{
> +    if ( IS_ENABLED(CONFIG_PV_SHIM_EXCLUSIVE) )
> +        return true;
> +
> +    return evaluate_nospec(!(d->options & XEN_DOMCTL_CDF_not_hypercall_target));
> +}
> +
>  #define VM_ASSIST(d, t) (test_bit(VMASST_TYPE_ ## t, &(d)->vm_assist))
>  
>  static always_inline bool is_pv_domain(const struct domain *d)
> diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
> index 0b341efd18..f2205575ed 100644
> --- a/xen/include/xsm/dummy.h
> +++ b/xen/include/xsm/dummy.h
> @@ -91,12 +91,16 @@ static always_inline int xsm_default_action(
>              return 0;
>          fallthrough;
>      case XSM_DM_PRIV:
> +        if ( target && !is_hypercall_target(target) )
> +            return -EPERM;
>          if ( is_dm_domain(src) )
>              return 0;
>          if ( target && evaluate_nospec(src->target == target) )
>              return 0;
>          fallthrough;
>      case XSM_PRIV:
> +        if ( target && !is_hypercall_target(target) )
> +            return -EPERM;
>          if ( is_control_domain(src) )
>              return 0;
>          return -EPERM;
> -- 
> 2.50.0
> 
>