CHECKPOLICY ?= checkpolicy
M4 ?= m4
+# Output security policy version. Leave unset to autodetect.
+OUTPUT_POLICY ?= $(BEST_POLICY_VER)
+
########################################
#
# End of configuration options
#
########################################
-# Policy version
-# By default, checkpolicy creates the highest version policy it supports. Force
-# the use of version 24 which is the highest that Xen supports, and the first to
-# include the Xen policy type (needed for static device policy).
-OUTPUT_POLICY = 24
-
POLICY_FILENAME = xenpolicy-$(shell $(MAKE) -C $(XEN_ROOT)/xen xenversion --no-print-directory)
POLICY_LOADPATH = /boot
+# List of policy versions supported by the hypervisor
+POLICY_VER_LIST_HV = 24 30
+
# policy source layout
POLDIR := policy
MODDIR := $(POLDIR)/modules
# checkpolicy can use the #line directives provided by -s for error reporting:
M4PARAM := -D self_contained_policy -s
+
+# The output of checkpolicy -V is "30 (compatibility range 30-15)", and the
+# first word of the output is the maximum policy version supported.
+CHECKPOLICY_VER_MAX := $(firstword $(shell $(CHECKPOLICY) -V))
+
+# Find the highest version supported by both the hypervisor and checkpolicy
+BEST_POLICY_VER := $(shell best=24; for ver in $(POLICY_VER_LIST_HV); do if test $$ver -le $(CHECKPOLICY_VER_MAX); then best=$$ver; fi; done; echo $$best)
+
CHECKPOLICY_PARAM := -t Xen -c $(OUTPUT_POLICY)
# enable MLS if requested.
uint32_t sid;
};
+struct xen_flask_devicetree_label {
+ /* IN */
+ uint32_t sid;
+ uint32_t length;
+ XEN_GUEST_HANDLE(char) path;
+};
+
struct xen_flask_op {
uint32_t cmd;
#define FLASK_LOAD 1
#define FLASK_DEL_OCONTEXT 22
#define FLASK_GET_PEER_SID 23
#define FLASK_RELABEL_DOMAIN 24
+#define FLASK_DEVICETREE_LABEL 25
uint32_t interface_version; /* XEN_FLASK_INTERFACE_VERSION */
union {
struct xen_flask_load load;
struct xen_flask_ocontext ocontext;
struct xen_flask_peersid peersid;
struct xen_flask_relabel relabel;
+ struct xen_flask_devicetree_label devicetree_label;
} u;
};
typedef struct xen_flask_op xen_flask_op_t;
return ret;
}
+static int flask_devicetree_label(struct xen_flask_devicetree_label *arg)
+{
+ int rv;
+ char *buf;
+ u32 sid = arg->sid;
+ u32 perm = sid ? SECURITY__ADD_OCONTEXT : SECURITY__DEL_OCONTEXT;
+
+ rv = domain_has_security(current->domain, perm);
+ if ( rv )
+ return rv;
+
+ rv = flask_copyin_string(arg->path, &buf, arg->length, PAGE_SIZE);
+ if ( rv )
+ return rv;
+
+ /* buf is consumed or freed by this function */
+ rv = security_devicetree_setlabel(buf, sid);
+
+ return rv;
+}
+
#ifndef COMPAT
static int flask_ocontext_del(struct xen_flask_ocontext *arg)
rv = flask_relabel_domain(&op.u.relabel);
break;
+ case FLASK_DEVICETREE_LABEL:
+ rv = flask_devicetree_label(&op.u.devicetree_label);
+ break;
+
default:
rv = -ENOSYS;
}
#define flask_security_get_bool compat_security_get_bool
#define flask_security_set_bool compat_security_set_bool
+#define xen_flask_devicetree_label compat_flask_devicetree_label
+#define flask_devicetree_label compat_devicetree_label
+
#define xen_flask_op_t compat_flask_op_t
#undef ret_t
#define ret_t int
#define POLICYDB_VERSION_POLCAP 22
#define POLICYDB_VERSION_PERMISSIVE 23
#define POLICYDB_VERSION_BOUNDARY 24
+#define POLICYDB_VERSION_FILENAME_TRANS 25
+#define POLICYDB_VERSION_ROLETRANS 26
+#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
+#define POLICYDB_VERSION_DEFAULT_TYPE 28
+#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
+#define POLICYDB_VERSION_XEN_DEVICETREE 30
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_XEN_DEVICETREE
enum flask_bootparam_t {
FLASK_BOOTPARAM_PERMISSIVE,
int security_device_sid(u32 device, u32 *out_sid);
+int security_devicetree_sid(const char *path, u32 *out_sid);
+
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass);
int security_ocontext_add(u32 ocontext, unsigned long low,
unsigned long high, u32 sid);
-int security_ocontext_del(u32 ocontext, unsigned int low, unsigned int high);
+int security_ocontext_del(u32 ocontext, unsigned long low, unsigned long high);
+
+int security_devicetree_setlabel(char *path, u32 sid);
#endif /* _FLASK_SECURITY_H_ */
{
.version = POLICYDB_VERSION_BASE,
.sym_num = SYM_NUM - 3,
- .ocon_num = OCON_NUM - 1,
+ .ocon_num = 4,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_BOOL,
.sym_num = SYM_NUM - 2,
- .ocon_num = OCON_NUM - 1,
+ .ocon_num = 4,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_IPV6,
.sym_num = SYM_NUM - 2,
- .ocon_num = OCON_NUM,
+ .ocon_num = 5,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_NLCLASS,
.sym_num = SYM_NUM - 2,
- .ocon_num = OCON_NUM,
+ .ocon_num = 5,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_MLS,
.sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .ocon_num = 5,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_AVTAB,
.sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .ocon_num = 5,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_RANGETRANS,
.sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .ocon_num = 5,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_POLCAP,
.sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .ocon_num = 5,
.target_type = TARGET_XEN_OLD,
},
{
.version = POLICYDB_VERSION_PERMISSIVE,
.sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .ocon_num = 5,
.target_type = TARGET_XEN_OLD,
},
{
{
.version = POLICYDB_VERSION_BOUNDARY,
.sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .ocon_num = OCON_DEVICE + 1,
+ .target_type = TARGET_XEN,
+ },
+ {
+ .version = POLICYDB_VERSION_XEN_DEVICETREE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_DTREE + 1,
.target_type = TARGET_XEN,
},
};
{
context_destroy(&c->context[0]);
context_destroy(&c->context[1]);
- if ( i == OCON_ISID )
+ if ( i == OCON_ISID || i == OCON_DTREE )
xfree(c->u.name);
xfree(c);
}
goto out;
}
-static int read_cons_helper(struct constraint_node **nodep, int ncons,
- int allowxtarget, void *fp)
+static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
+ int ncons, int allowxtarget, void *fp)
{
struct constraint_node *c, *lc;
struct constraint_expr *e, *le;
depth++;
if ( ebitmap_read(&e->names, fp) )
return -EINVAL;
+ if ( p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES )
+ {
+ struct ebitmap dummy;
+ ebitmap_init(&dummy);
+ if ( ebitmap_read(&dummy, fp) )
+ return -EINVAL;
+ ebitmap_destroy(&dummy);
+
+ ebitmap_init(&dummy);
+ if ( ebitmap_read(&dummy, fp) )
+ return -EINVAL;
+ ebitmap_destroy(&dummy);
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ return rc;
+ }
break;
default:
return -EINVAL;
goto bad;
}
- rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
+ rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
if ( rc )
goto bad;
if ( rc < 0 )
goto bad;
ncons = le32_to_cpu(buf[0]);
- rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
+ rc = read_cons_helper(p, &cladatum->validatetrans, ncons, 1, fp);
if ( rc )
goto bad;
}
+ if ( p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS )
+ {
+ rc = next_entry(buf, fp, sizeof(u32) * 3);
+ if ( rc )
+ goto bad;
+ /* these values are ignored by Xen */
+ }
+
+ if ( p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE )
+ {
+ rc = next_entry(buf, fp, sizeof(u32) * 1);
+ if ( rc )
+ goto bad;
+ /* ignored by Xen */
+ }
+
rc = hashtab_insert(h, key, cladatum);
if ( rc )
goto bad;
ltr->next = tr;
else
p->role_tr = tr;
- rc = next_entry(buf, fp, sizeof(u32)*3);
+ if ( p->policyvers >= POLICYDB_VERSION_ROLETRANS )
+ rc = next_entry(buf, fp, sizeof(u32)*4);
+ else
+ rc = next_entry(buf, fp, sizeof(u32)*3);
if ( rc < 0 )
goto bad;
tr->role = le32_to_cpu(buf[0]);
lra = ra;
}
+ if ( p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS )
+ {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc )
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+ if ( nel )
+ {
+ printk(KERN_ERR "Flask: unsupported genfs config data\n");
+ rc = -EINVAL;
+ goto bad;
+ }
+ }
+
rc = policydb_index_classes(p);
if ( rc )
goto bad;
"Old xen policy does not support iomemcon");
goto bad;
}
- rc = next_entry(buf, fp, sizeof(u32) *2);
- if ( rc < 0 )
- goto bad;
- c->u.iomem.low_iomem = le32_to_cpu(buf[0]);
- c->u.iomem.high_iomem = le32_to_cpu(buf[1]);
+ if ( p->policyvers >= POLICYDB_VERSION_XEN_DEVICETREE )
+ {
+ u64 b64[2];
+ rc = next_entry(b64, fp, sizeof(u64) *2);
+ if ( rc < 0 )
+ goto bad;
+ c->u.iomem.low_iomem = le64_to_cpu(b64[0]);
+ c->u.iomem.high_iomem = le64_to_cpu(b64[1]);
+ }
+ else
+ {
+ rc = next_entry(buf, fp, sizeof(u32) *2);
+ if ( rc < 0 )
+ goto bad;
+ c->u.iomem.low_iomem = le32_to_cpu(buf[0]);
+ c->u.iomem.high_iomem = le32_to_cpu(buf[1]);
+ }
rc = context_read_and_validate(&c->context[0], p, fp);
if ( rc )
goto bad;
if ( rc )
goto bad;
break;
+ case OCON_DTREE:
+ if ( p->target_type != TARGET_XEN )
+ {
+ printk(KERN_ERR
+ "Old xen policy does not support devicetreecon");
+ goto bad;
+ }
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ len = le32_to_cpu(buf[0]);
+ rc = -ENOMEM;
+ c->u.name = xmalloc_array(char, len + 1);
+ if (!c->u.name)
+ goto bad;
+ rc = next_entry(c->u.name, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ c->u.name[len] = 0;
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if ( rc )
+ goto bad;
+ break;
default:
printk(KERN_ERR
"Flask: unsupported object context config data\n");
u32 high_ioport;
} ioport;
struct {
- u32 low_iomem;
- u32 high_iomem;
+ u64 low_iomem;
+ u64 high_iomem;
} iomem;
} u;
struct context context[2]; /* security context(s) */
#define OCON_IOPORT 2 /* io ports */
#define OCON_IOMEM 3 /* io memory */
#define OCON_DEVICE 4 /* pci devices */
-#define OCON_NUM 5
+#define OCON_DTREE 5 /* device tree nodes */
+#define OCON_NUM 6
#define OCON_NUM_OLD 7
/* The policy database */
return rc;
}
+int security_devicetree_sid(const char *path, u32 *out_sid)
+{
+ struct ocontext *c;
+ int rc = 0;
+
+ POLICY_RDLOCK;
+
+ c = policydb.ocontexts[OCON_DTREE];
+ while ( c )
+ {
+ if ( strcmp(c->u.name, path) == 0 )
+ break;
+ c = c->next;
+ }
+
+ if ( c )
+ {
+ if ( !c->sid[0] )
+ {
+ rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+ if ( rc )
+ goto out;
+ }
+ *out_sid = c->sid[0];
+ }
+ else
+ {
+ *out_sid = SECINITSID_DEVICE;
+ }
+
+out:
+ POLICY_RDUNLOCK;
+ return rc;
+}
+
int security_find_bool(const char *name)
{
int i, rv = -ENOENT;
c->u.iomem.high_iomem == high && c->sid[0] == sid)
break;
- printk("%s: IO Memory overlap with entry %#x - %#x\n",
- __FUNCTION__, c->u.iomem.low_iomem,
- c->u.iomem.high_iomem);
+ printk("%s: IO Memory overlap with entry %#"PRIx64" - %#"PRIx64"\n",
+ __FUNCTION__, c->u.iomem.low_iomem, c->u.iomem.high_iomem);
ret = -EEXIST;
break;
}
return ret;
}
-int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high )
+int security_ocontext_del( u32 ocon, unsigned long low, unsigned long high )
{
int ret = 0;
struct ocontext *c, *before_c;
}
}
- printk("%s: ocontext not found: pirq %d\n", __FUNCTION__, low);
+ printk("%s: ocontext not found: pirq %ld\n", __FUNCTION__, low);
ret = -ENOENT;
break;
}
}
- printk("%s: ocontext not found: ioport %#x - %#x\n", __FUNCTION__,
- low, high);
+ printk("%s: ocontext not found: ioport %#lx - %#lx\n",
+ __FUNCTION__, low, high);
ret = -ENOENT;
break;
}
}
- printk("%s: ocontext not found: iomem %#x - %#x\n", __FUNCTION__,
- low, high);
+ printk("%s: ocontext not found: iomem %#lx - %#lx\n",
+ __FUNCTION__, low, high);
ret = -ENOENT;
break;
}
}
- printk("%s: ocontext not found: pcidevice %#x\n", __FUNCTION__, low);
+ printk("%s: ocontext not found: pcidevice %#lx\n", __FUNCTION__, low);
ret = -ENOENT;
break;
POLICY_WRUNLOCK;
return ret;
}
+
+int security_devicetree_setlabel(char *path, u32 sid)
+{
+ int ret = 0;
+ struct ocontext *c;
+ struct ocontext **pcurr;
+ struct ocontext *add = NULL;
+
+ if ( sid )
+ {
+ add = xzalloc(struct ocontext);
+ if ( add == NULL )
+ {
+ xfree(path);
+ return -ENOMEM;
+ }
+ add->sid[0] = sid;
+ add->u.name = path;
+ }
+ else
+ {
+ ret = -ENOENT;
+ }
+
+ POLICY_WRLOCK;
+
+ pcurr = &policydb.ocontexts[OCON_DTREE];
+ c = *pcurr;
+ while ( c )
+ {
+ if ( strcmp(c->u.name, path) == 0 )
+ {
+ if ( sid )
+ {
+ ret = -EEXIST;
+ break;
+ }
+ else
+ {
+ *pcurr = c->next;
+ xfree(c->u.name);
+ xfree(c);
+ ret = 0;
+ break;
+ }
+ }
+ pcurr = &c->next;
+ c = *pcurr;
+ }
+
+ if ( add && ret == 0 )
+ {
+ add->next = policydb.ocontexts[OCON_DTREE];
+ policydb.ocontexts[OCON_DTREE] = add;
+ add = NULL;
+ path = NULL;
+ }
+
+ POLICY_WRUNLOCK;
+
+ xfree(add);
+ xfree(path);
+ return ret;
+}