diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 822848fd37..d674a152f2 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -1025,6 +1026,7 @@ static arm_hypercall_t arm_hypercall_table[] = { HYPERCALL(sysctl, 2), HYPERCALL(hvm_op, 2), HYPERCALL(grant_table_op, 3), + HYPERCALL(multicall, 2), HYPERCALL_ARM(vcpu_op, 3), }; @@ -1172,6 +1174,24 @@ static void do_trap_hypercall(struct cpu_user_regs *regs, register_t *nr, #endif } +static bool_t check_multicall_32bit_clean(struct multicall_entry *multi) +{ + int i; + + for ( i = 0; i < arm_hypercall_table[multi->op].nr_args; i++ ) + { + if ( unlikely(multi->args[i] & 0xffffffff00000000ULL) ) + { + printk("%pv: multicall argument %d is not 32-bit clean %"PRIx64"\n", + current, i, multi->args[i]); + domain_crash(current->domain); + return false; + } + } + + return true; +} + void do_multicall_call(struct multicall_entry *multi) { arm_hypercall_fn_t call = NULL; @@ -1189,9 +1209,13 @@ void do_multicall_call(struct multicall_entry *multi) return; } + if ( is_32bit_domain(current->domain) && + !check_multicall_32bit_clean(multi) ) + return; + multi->result = call(multi->args[0], multi->args[1], - multi->args[2], multi->args[3], - multi->args[4]); + multi->args[2], multi->args[3], + multi->args[4]); } /* diff --git a/xen/common/compat/multicall.c b/xen/common/compat/multicall.c index 95c047a50a..2af8aef8b7 100644 --- a/xen/common/compat/multicall.c +++ b/xen/common/compat/multicall.c @@ -29,7 +29,7 @@ DEFINE_XEN_GUEST_HANDLE(multicall_entry_compat_t); static void __trace_multicall_call(multicall_entry_t *call) { - unsigned long args[6]; + xen_ulong_t args[6]; int i; for ( i = 0; i < ARRAY_SIZE(args); i++ ) diff --git a/xen/common/multicall.c b/xen/common/multicall.c index e66c798236..fa9d910594 100644 --- a/xen/common/multicall.c +++ b/xen/common/multicall.c @@ -35,10 +35,10 @@ static void trace_multicall_call(multicall_entry_t *call) ret_t do_multicall( - XEN_GUEST_HANDLE_PARAM(multicall_entry_t) call_list, unsigned int nr_calls) + XEN_GUEST_HANDLE_PARAM(multicall_entry_t) call_list, uint32_t nr_calls) { struct mc_state *mcs = ¤t->mc_state; - unsigned int i; + uint32_t i; int rc = 0; if ( unlikely(__test_and_set_bit(_MCSF_in_multicall, &mcs->flags)) ) diff --git a/xen/common/trace.c b/xen/common/trace.c index 1814165f9b..f651cf36dd 100644 --- a/xen/common/trace.c +++ b/xen/common/trace.c @@ -817,7 +817,7 @@ unlock: } void __trace_hypercall(uint32_t event, unsigned long op, - const unsigned long *args) + const xen_ulong_t *args) { struct __packed { uint32_t op; diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 8c5697e16c..a6a20926a5 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -541,13 +541,15 @@ DEFINE_XEN_GUEST_HANDLE(mmu_update_t); /* * ` enum neg_errnoval * ` HYPERVISOR_multicall(multicall_entry_t call_list[], - * ` unsigned int nr_calls); + * ` uint32_t nr_calls); * - * NB. The fields are natural register size for this architecture. + * NB. The fields are logically the natural register size for this + * architecture. In cases where xen_ulong_t is larger than this then + * any unused bits in the upper portion must be zero. */ struct multicall_entry { - unsigned long op, result; - unsigned long args[6]; + xen_ulong_t op, result; + xen_ulong_t args[6]; }; typedef struct multicall_entry multicall_entry_t; DEFINE_XEN_GUEST_HANDLE(multicall_entry_t); diff --git a/xen/include/xen/trace.h b/xen/include/xen/trace.h index 3b8a7b39da..12966eaa1d 100644 --- a/xen/include/xen/trace.h +++ b/xen/include/xen/trace.h @@ -45,7 +45,7 @@ static inline void trace_var(u32 event, int cycles, int extra, } void __trace_hypercall(uint32_t event, unsigned long op, - const unsigned long *args); + const xen_ulong_t *args); /* Convenience macros for calling the trace function. */ #define TRACE_0D(_e) \