|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v4] xen: introduce CONFIG_HAS_SHARED_INFO for archs without a shared page
On 25.06.2026 18:02, Oleksii Kurochko wrote:
> On architectures that run guests in dom0less mode without the PV ABI
> (currently RISC-V), no shared_info page is allocated and d->shared_info
> remains NULL throughout the domain lifetime. Several places in common
> code access d->shared_info through the shared_info() macro or directly,
> causing UBSAN null-pointer errors on such architectures.
>
> Rather than adding runtime NULL guards that are logically unreachable
> on x86 and Arm (where shared_info is always allocated), introduce a new
> Kconfig symbol CONFIG_HAS_SHARED_INFO selected by x86 and Arm.
>
> On !HAS_SHARED_INFO the shared_info() macro expands to a dereference
> of a pointer returned by shared_info_absent(), which is declared but
> intentionally never defined.
This looks to need updating.
> Any use of shared_info() that is not
> dead-code-eliminated will therefore cause a link-time failure, making
> missed guards impossible to overlook.
>
> The 2L event-channel ops call shared_info() and must not be compiled on
> architectures without a shared_info page, so event_2l.o is gated on
> CONFIG_HAS_SHARED_INFO. On such architectures evtchn_init() installs
> the FIFO ops as a placeholder instead; evtchn_fifo_word_from_port() is
> guarded against uninitialised d->evtchn_fifo so the FIFO ops are safe
> before evtchn_fifo_init_control() is called by the guest.
>
> With CONFIG_HAS_SHARED_INFO=n all vCPUs fall back to the global
> dummy_vcpu_info, so writes through vcpu_info() could leak data between
> vCPUs. Reviewing the write paths in common code: the write in
> map_guest_area() stores the constant ~0 so nothing serious would happen
> if it were leaked; the event_2l.c paths are unreachable because the
> preceding shared_info() call would trap first;
Why "trap"? You can't build an image that way, can you?
> @@ -1624,7 +1626,11 @@ void evtchn_check_pollers(struct domain *d, unsigned
> int port)
>
> int evtchn_init(struct domain *d, unsigned int max_port)
> {
> - evtchn_2l_init(d);
> + if ( IS_ENABLED(CONFIG_HAS_SHARED_INFO) )
> + evtchn_2l_init(d);
For this to build when !HAS_SHARED_INFO, all you need is a declaration of
the function. The compiler will DCE the call. Hence ...
> --- a/xen/common/event_channel.h
> +++ b/xen/common/event_channel.h
> @@ -44,7 +44,11 @@ static inline void evtchn_port_print_state(struct domain
> *d,
>
> /* 2-level */
>
> +#ifdef CONFIG_HAS_SHARED_INFO
> void evtchn_2l_init(struct domain *d);
> +#else
> +static inline void evtchn_2l_init(struct domain *d) {}
> +#endif
>
> /* FIFO */
>
... this hunk should be unnecessary?
> @@ -55,6 +59,7 @@ struct evtchn_expand_array;
> int evtchn_fifo_init_control(struct evtchn_init_control *init_control);
> int evtchn_fifo_expand_array(const struct evtchn_expand_array *expand_array);
> void evtchn_fifo_destroy(struct domain *d);
> +void evtchn_fifo_init_ops(struct domain *d);
> #else
> static inline int evtchn_fifo_init_control(struct evtchn_init_control
> *init_control)
> {
> @@ -68,6 +73,7 @@ static inline void evtchn_fifo_destroy(struct domain *d)
> {
> return;
> }
> +static inline void evtchn_fifo_init_ops(struct domain *d) {}
> #endif /* CONFIG_EVTCHN_FIFO */
Unlike these two. Which raise a different question though: What will be the
behavior when EVTCHN_FIFO=n and HAS_SHARED_INFO=n? Taking
evtchn_alloc_unbound() as example, afaict evtchn_port_init() will stumble
over a NULL pointer. Looks like for that (and only that) case we still need
your earlier dummy fallback.
> @@ -420,6 +423,11 @@ static const struct evtchn_port_ops evtchn_port_ops_fifo
> =
> .print_state = evtchn_fifo_print_state,
> };
>
> +void evtchn_fifo_init_ops(struct domain *d)
> +{
> + d->evtchn_port_ops = &evtchn_port_ops_fifo;
> +}
Isn't this unreachable code when HAS_SHARED_INFO=y, violating Misra rule 2.1?
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |