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 @@ -181,12 +181,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 @@ -60,7 +60,6 @@ struct xsm_ops { int (*domctl)(struct domain *d, struct xen_domctl *op); #ifdef CONFIG_SYSCTL int (*sysctl)(const struct xen_sysctl *op); - int (*readconsole)(uint32_t clear); #endif int (*evtchn_unbound)(struct domain *d, struct evtchn *chn, domid_t id2); @@ -245,11 +244,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); -} #endif static inline int xsm_evtchn_unbound( --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -22,7 +22,6 @@ static const struct xsm_ops __initconst_ .domctl = xsm_domctl, #ifdef CONFIG_SYSCTL .sysctl = xsm_sysctl, - .readconsole = xsm_readconsole, #endif .evtchn_unbound = xsm_evtchn_unbound, --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -877,13 +877,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); @@ -949,16 +954,6 @@ static int cf_check flask_sysctl(const s return avc_unknown_permission("sysctl", op->cmd); } } - -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); -} #endif /* CONFIG_SYSCTL */ static inline uint32_t resource_to_perm(uint8_t access) @@ -1903,7 +1898,6 @@ static const struct xsm_ops __initconst_ .domctl = flask_domctl, #ifdef CONFIG_SYSCTL .sysctl = flask_sysctl, - .readconsole = flask_readconsole, #endif .evtchn_unbound = flask_evtchn_unbound,