@@ -1063,6 +1063,9 @@ void __init start_xen(unsigned long boot_phys_offset,
/* Hide UART from DOM0 if we're using it */
serial_endboot();
+ if ( (rc = xsm_set_system_active()) != 0 )
+ panic("xsm: unable to switch to SYSTEM_ACTIVE privilege: %d\n", rc);
+
system_state = SYS_STATE_active;
for_each_domain( d )
@@ -619,6 +619,10 @@ static void noreturn init_done(void)
{
void *va;
unsigned long start, end;
+ int err;
+
+ if ( (err = xsm_set_system_active()) != 0 )
+ panic("xsm: unable to switch to SYSTEM_ACTIVE privilege: %d\n", err);
system_state = SYS_STATE_active;
@@ -3033,7 +3033,12 @@ void __init scheduler_init(void)
sched_ratelimit_us = SCHED_DEFAULT_RATELIMIT_US;
}
- idle_domain = domain_create(DOMID_IDLE, NULL, 0);
+ /*
+ * The idle dom is created privileged to ensure unrestricted access during
+ * setup and will be demoted by xsm_set_system_active() when setup is
+ * complete.
+ */
+ idle_domain = domain_create(DOMID_IDLE, NULL, CDF_privileged);
BUG_ON(IS_ERR(idle_domain));
BUG_ON(nr_cpu_ids > ARRAY_SIZE(idle_vcpu));
idle_domain->vcpu = idle_vcpu;
@@ -101,6 +101,23 @@ static always_inline int xsm_default_action(
}
}
+static XSM_INLINE int cf_check xsm_set_system_active(void)
+{
+ struct domain *d = current->domain;
+
+ ASSERT(d->is_privileged);
+
+ if ( d->domain_id != DOMID_IDLE )
+ {
+ printk("%s: should only be called by idle domain\n", __func__);
+ return -EPERM;
+ }
+
+ d->is_privileged = false;
+
+ return 0;
+}
+
static XSM_INLINE void cf_check xsm_security_domaininfo(
struct domain *d, struct xen_domctl_getdomaininfo *info)
{
@@ -52,6 +52,7 @@ typedef enum xsm_default xsm_default_t;
* !!! WARNING !!!
*/
struct xsm_ops {
+ int (*set_system_active)(void);
void (*security_domaininfo)(struct domain *d,
struct xen_domctl_getdomaininfo *info);
int (*domain_create)(struct domain *d, uint32_t ssidref);
@@ -208,6 +209,11 @@ extern struct xsm_ops xsm_ops;
#ifndef XSM_NO_WRAPPERS
+static inline int xsm_set_system_active(void)
+{
+ return alternative_call(xsm_ops.set_system_active);
+}
+
static inline void xsm_security_domaininfo(
struct domain *d, struct xen_domctl_getdomaininfo *info)
{
@@ -14,6 +14,7 @@
#include <xsm/dummy.h>
static const struct xsm_ops __initconst_cf_clobber dummy_ops = {
+ .set_system_active = xsm_set_system_active,
.security_domaininfo = xsm_security_domaininfo,
.domain_create = xsm_domain_create,
.getdomaininfo = xsm_getdomaininfo,
@@ -191,6 +191,28 @@ static int cf_check flask_domain_alloc_security(struct domain *d)
return 0;
}
+static int cf_check flask_set_system_active(void)
+{
+ struct domain *d = current->domain;
+
+ ASSERT(d->is_privileged);
+
+ if ( d->domain_id != DOMID_IDLE )
+ {
+ printk("%s: should only be called by idle domain\n", __func__);
+ return -EPERM;
+ }
+
+ /*
+ * While is_privileged has no significant meaning under flask, set to false
+ * as is_privileged is not only used for a privilege check but also as a
+ * type of domain check, specifically if the domain is the control domain.
+ */
+ d->is_privileged = false;
+
+ return 0;
+}
+
static void cf_check flask_domain_free_security(struct domain *d)
{
struct domain_security_struct *dsec = d->ssid;
@@ -1774,6 +1796,7 @@ static int cf_check flask_argo_send(
#endif
static const struct xsm_ops __initconst_cf_clobber flask_ops = {
+ .set_system_active = flask_set_system_active,
.security_domaininfo = flask_security_domaininfo,
.domain_create = flask_domain_create,
.getdomaininfo = flask_getdomaininfo,