From: Jan Beulich Subject: sysctl/XSM: drop .readconsole() hook Integrate the checking with xsm_sysctl(), now that it has the full op struct passed. As a positive side effect, permissions are then checked at the same early point with and without Flask. This is part of CVE-2026-62426 / XSA-499. Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Acked-By: Daniel P. Smith --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -59,10 +59,6 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xe switch ( op->cmd ) { case XEN_SYSCTL_readconsole: - ret = xsm_readconsole(XSM_HOOK, op->u.readconsole.clear); - if ( ret ) - break; - ret = read_console_ring(&op->u.readconsole); break; --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -180,12 +180,6 @@ static XSM_INLINE int cf_check xsm_sysct return xsm_default_action(action, current->domain, NULL); } -static XSM_INLINE int cf_check xsm_readconsole(XSM_DEFAULT_ARG uint32_t clear) -{ - XSM_ASSERT_ACTION(XSM_HOOK); - return xsm_default_action(action, current->domain, NULL); -} - static XSM_INLINE int cf_check xsm_alloc_security_domain(struct domain *d) { return 0; --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -59,7 +59,6 @@ struct xsm_ops { int (*set_target)(struct domain *d, struct domain *e); int (*domctl)(struct domain *d, struct xen_domctl *op); int (*sysctl)(const struct xen_sysctl *op); - int (*readconsole)(uint32_t clear); int (*evtchn_unbound)(struct domain *d, struct evtchn *chn, domid_t id2); int (*evtchn_interdomain)(struct domain *d1, struct evtchn *chn1, @@ -237,11 +236,6 @@ static inline int xsm_sysctl(xsm_default return alternative_call(xsm_ops.sysctl, op); } -static inline int xsm_readconsole(xsm_default_t def, uint32_t clear) -{ - return alternative_call(xsm_ops.readconsole, clear); -} - static inline int xsm_evtchn_unbound( xsm_default_t def, struct domain *d1, struct evtchn *chn, domid_t id2) { --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -21,7 +21,6 @@ static const struct xsm_ops __initconst_ .set_target = xsm_set_target, .domctl = xsm_domctl, .sysctl = xsm_sysctl, - .readconsole = xsm_readconsole, .evtchn_unbound = xsm_evtchn_unbound, .evtchn_interdomain = xsm_evtchn_interdomain, --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -906,13 +906,18 @@ static int cf_check flask_sysctl(const s switch ( op->cmd ) { /* These have individual XSM hooks */ - case XEN_SYSCTL_readconsole: case XEN_SYSCTL_page_offline_op: #ifdef CONFIG_X86 case XEN_SYSCTL_cpu_hotplug: #endif return 0; + case XEN_SYSCTL_readconsole: + return domain_has_xen(current->domain, + XEN__READCONSOLE | + (op->u.readconsole.clear ? XEN__CLEARCONSOLE + : 0)); + case XEN_SYSCTL_tbuf_op: return domain_has_xen(current->domain, XEN__TBUFCONTROL); @@ -983,16 +988,6 @@ static int cf_check flask_sysctl(const s } } -static int cf_check flask_readconsole(uint32_t clear) -{ - uint32_t perms = XEN__READCONSOLE; - - if ( clear ) - perms |= XEN__CLEARCONSOLE; - - return domain_has_xen(current->domain, perms); -} - static inline uint32_t resource_to_perm(uint8_t access) { if ( access ) @@ -1923,7 +1918,6 @@ static const struct xsm_ops __initconst_ .set_target = flask_set_target, .domctl = flask_domctl, .sysctl = flask_sysctl, - .readconsole = flask_readconsole, .evtchn_unbound = flask_evtchn_unbound, .evtchn_interdomain = flask_evtchn_interdomain,