aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/misc/xsm-flask.txt64
-rw-r--r--tools/flask/policy/Makefile16
-rw-r--r--tools/flask/policy/policy/modules/xen/xen.if31
-rw-r--r--tools/flask/policy/policy/modules/xen/xen.te35
-rw-r--r--xen/xsm/flask/avc.c2
-rw-r--r--xen/xsm/flask/hooks.c31
-rw-r--r--xen/xsm/flask/include/avc.h6
-rw-r--r--xen/xsm/flask/ss/policydb.c71
-rw-r--r--xen/xsm/flask/ss/policydb.h23
-rw-r--r--xen/xsm/flask/ss/services.c9
10 files changed, 261 insertions, 27 deletions
diff --git a/docs/misc/xsm-flask.txt b/docs/misc/xsm-flask.txt
index 284ad9c1d2..976e7c085d 100644
--- a/docs/misc/xsm-flask.txt
+++ b/docs/misc/xsm-flask.txt
@@ -168,6 +168,70 @@ adding them to xen.te, although manual review is advised and will
often lead to adding parameterized rules to the interfaces in xen.if
to address the general case.
+Device Policy
+-------------
+
+Flask is capable of labeling devices and enforcing policies associated with
+them. To enable this functionality the latest version of checkpolicy
+(>= 2.0.20) and libsepol (>=2.0.39) will be needed in order to compile it. To
+enable the building of the new policies the following changes will need to be
+done to tools/flask/policy/Makefile.
+
+########################################
+#
+# Build a binary policy locally
+#
+$(POLVER): policy.conf
+ @echo "Compiling $(NAME) $(POLVER)"
+ $(QUIET) $(CHECKPOLICY) $^ -o $@ (Comment out this line)
+# Uncomment line below to enable policies for devices
+# $(QUIET) $(CHECKPOLICY) -t Xen $^ -o $@ (Uncomment this line)
+
+########################################
+#
+# Install a binary policy
+#
+$(LOADPATH): policy.conf
+ @echo "Compiling and installing $(NAME) $(LOADPATH)"
+ $(QUIET) $(CHECKPOLICY) $^ -o $@ (Comment out this line)
+# Uncomment line below to enable policies for devices
+# $(QUIET) $(CHECKPOLICY) -t Xen $^ -o $@ (Uncomment this line)
+
+
+Pirqs, PCI devices, I/O memory and ports can all be labeled. There are
+commented out lines in xen.te policy for examples on how to label devices.
+
+Device Labeling
+---------------
+
+The "lspci -vvn" command can be used to output all the devices and identifiers
+associated with them. For example, to label an Intel e1000e ethernet card the
+lspci output is..
+
+00:19.0 0200: 8086:10de (rev 02)
+ Subsystem: 1028:0276
+ Interrupt: pin A routed to IRQ 33
+ Region 0: Memory at febe0000 (32-bit, non-prefetchable) [size=128K]
+ Region 1: Memory at febd9000 (32-bit, non-prefetchable) [size=4K]
+ Region 2: I/O ports at ecc0 [size=32]
+ Kernel modules: e1000e
+
+The labeling can be done with these commands
+
+pirqcon 33 system_u:object_r:nicP_t
+iomemcon 0xfebe0-0xfebff system_u:object_r:nicP_t
+iomemcon 0xfebd9 system_u:object_r:nicP_t
+ioportcon 0xecc0-0xecdf system_u:object_r:nicP_t
+pcidevicecon 0xc800 system_u:object_r:nicP_t
+
+Labeling of the PCI device is tricky since there is no output in lspci that
+makes the information easily available. The easiest way to obtain the
+information is to look at the avc denial line for the correct hex value.
+
+(XEN) avc: denied { add_device } for domid=0 device=0xc800 <---
+scontext=system_u:system_r:dom0_t tcontext=system_u:object_r:device_t
+tclass=resource
+
Additional notes on XSM:FLASK
-----------------------------
diff --git a/tools/flask/policy/Makefile b/tools/flask/policy/Makefile
index 1d227cc15f..4c0d428b57 100644
--- a/tools/flask/policy/Makefile
+++ b/tools/flask/policy/Makefile
@@ -149,6 +149,8 @@ load: tmp/load
$(POLVER): policy.conf
@echo "Compiling $(NAME) $(POLVER)"
$(QUIET) $(CHECKPOLICY) $^ -o $@
+# Uncomment line below to enable policies for devices
+# $(QUIET) $(CHECKPOLICY) -t Xen $^ -o $@
########################################
#
@@ -157,6 +159,8 @@ $(POLVER): policy.conf
$(LOADPATH): policy.conf
@echo "Compiling and installing $(NAME) $(LOADPATH)"
$(QUIET) $(CHECKPOLICY) $^ -o $@
+# Uncomment line below to enable policies for devices
+# $(QUIET) $(CHECKPOLICY) -t Xen $^ -o $@
########################################
#
@@ -206,8 +210,18 @@ tmp/all_attrs_types.conf tmp/only_te_rules.conf tmp/all_post.conf: tmp/all_te_fi
$(QUIET) grep '^type ' tmp/all_te_files.conf >> tmp/all_attrs_types.conf
$(QUIET) cat tmp/post_te_files.conf > tmp/all_post.conf
$(QUIET) grep '^sid ' tmp/all_te_files.conf >> tmp/all_post.conf || true
+ $(QUIET) grep ^pirqcon tmp/all_te_files.conf >> \
+ tmp/all_post.conf || true
+ $(QUIET) grep ^ioportcon tmp/all_te_files.conf >> \
+ tmp/all_post.conf || true
+ $(QUIET) grep ^iomemcon tmp/all_te_files.conf >> \
+ tmp/all_post.conf || true
+ $(QUIET) grep ^pcidevicecon tmp/all_te_files.conf >> \
+ tmp/all_post.conf || true
$(QUIET) sed -r -e /^attribute/d -e '/^type /d' -e '/^sid /d' \
- < tmp/all_te_files.conf > tmp/only_te_rules.conf
+ -e "/^pirqcon/d" -e "/^pcidevicecon/d" -e "/^ioportcon/d" \
+ -e "/^iomemcon/d" < tmp/all_te_files.conf \
+ > tmp/only_te_rules.conf
########################################
#
diff --git a/tools/flask/policy/policy/modules/xen/xen.if b/tools/flask/policy/policy/modules/xen/xen.if
index a4ab005087..99afad6f6b 100644
--- a/tools/flask/policy/policy/modules/xen/xen.if
+++ b/tools/flask/policy/policy/modules/xen/xen.if
@@ -60,3 +60,34 @@ define(`create_channel', `
allow $1 $3:event {create};
allow $3 $2:event {bind};
')
+###############################################################################
+#
+# create_passthrough_resource(priv_dom, domain, resource)
+#
+###############################################################################
+define(`create_passthrough_resource', `
+ type $3, resource_type;
+ allow $1 $3:event vector;
+ allow $1 $2:resource {add remove};
+ allow $1 ioport_t:resource {add_ioport use};
+ allow $1 iomem_t:resource {add_iomem use};
+ allow $1 pirq_t:resource {add_irq use};
+ allow $1 domio_t:mmu {map_read map_write};
+ allow $2 domio_t:mmu {map_write};
+ allow $2 pirq_t:resource {use};
+ allow $1 $3:resource {add_irq add_iomem add_ioport remove_irq remove_iomem remove_ioport use add_device remove_device};
+ allow $2 $3:resource {use add_ioport add_iomem remove_ioport remove_iomem};
+ allow $2 $3:mmu {map_read map_write};
+')
+###############################################################################
+#
+# create_hvm_resource(priv_dom, domain, resource)
+#
+###############################################################################
+define(`create_hvm_resource', `
+ type $3, resource_type;
+ allow $1 $2:resource {add remove};
+ allow $1 $3:hvm {bind_irq};
+ allow $1 $3:resource {stat_device add_device remove_device add_irq remove_irq add_iomem remove_iomem add_ioport remove_ioport};
+ allow $2 $3:resource {use};
+')
diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te
index e72e4e6e57..851b0d6bd3 100644
--- a/tools/flask/policy/policy/modules/xen/xen.te
+++ b/tools/flask/policy/policy/modules/xen/xen.te
@@ -76,6 +76,41 @@ allow dom0_t dom0_t:event {send};
allow dom0_t domU_t:grant {copy};
allow domU_t domU_t:grant {copy};
+###############################################################################
+#
+# Create device labels
+#
+###############################################################################
+
+# create device resources
+#create_passthrough_resource(dom0_t, domU_t, nicP_t)
+#create_hvm_resource(dom0_t, domHU_t, nicP_t)
+
+# label e1000e nic
+#pirqcon 33 system_u:object_r:nicP_t
+#pirqcon 55 system_u:object_r:nicP_t
+#iomemcon 0xfebe0-0xfebff system_u:object_r:nicP_t
+#iomemcon 0xfebd9 system_u:object_r:nicP_t
+#ioportcon 0xecc0-0xecdf system_u:object_r:nicP_t
+#pcidevicecon 0xc800 system_u:object_r:nicP_t
+
+# label e100 nic
+#pirqcon 16 system_u:object_r:nicP_t
+#iomemcon 0xfe5df system_u:object_r:nicP_t
+#iomemcon 0xfe5e0-0xfe5ff system_u:object_r:nicP_t
+#iomemcon 0xc2000-0xc200f system_u:object_r:nicP_t
+#ioportcon 0xccc0-0xcd00 system_u:object_r:nicP_t
+
+# label usb 1d.0-2 1d.7
+#pirqcon 23 system_u:object_r:nicP_t
+#pirqcon 17 system_u:object_r:nicP_t
+#pirqcon 18 system_u:object_r:nicP_t
+#ioportcon 0xff80-0xFF9F system_u:object_r:nicP_t
+#ioportcon 0xff60-0xff7f system_u:object_r:nicP_t
+#ioportcon 0xff40-0xff5f system_u:object_r:nicP_t
+#iomemcon 0xff980 system_u:object_r:nicP_t
+#ioportcon 0xff00-0xff1f system_u:object_r:nicP_t
+
manage_domain(dom0_t, domU_t)
################################################################################
diff --git a/xen/xsm/flask/avc.c b/xen/xsm/flask/avc.c
index ade2dd97b9..06a3c7dc92 100644
--- a/xen/xsm/flask/avc.c
+++ b/xen/xsm/flask/avc.c
@@ -566,6 +566,8 @@ void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
d = a->d;
if ( d )
printk("domid=%d ", d->domain_id);
+ if ( a && a->device )
+ printk("device=0x%lx ", a->device);
avc_dump_query(ssid, tsid, tclass);
printk("\n");
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index c2aaec80b6..b2bf4023f1 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -649,6 +649,7 @@ static int irq_has_perm(struct domain *d, uint8_t pirq, uint8_t access)
int rc = -EPERM;
struct domain_security_struct *ssec, *tsec;
+ struct avc_audit_data ad;
rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
resource_to_perm(access));
@@ -668,13 +669,16 @@ static int irq_has_perm(struct domain *d, uint8_t pirq, uint8_t access)
if ( rc )
return rc;
- rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+ AVC_AUDIT_DATA_INIT(&ad, DEV);
+ ad.device = (unsigned long) pirq;
+
+ rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad);
if ( rc )
return rc;
if ( access )
return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE,
- RESOURCE__USE, NULL);
+ RESOURCE__USE, &ad);
else
return rc;
}
@@ -686,6 +690,7 @@ static int iomem_has_perm(struct domain *d, unsigned long mfn, uint8_t access)
int rc = -EPERM;
struct domain_security_struct *ssec, *tsec;
+ struct avc_audit_data ad;
rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
resource_to_perm(access));
@@ -704,13 +709,16 @@ static int iomem_has_perm(struct domain *d, unsigned long mfn, uint8_t access)
if ( rc )
return rc;
- rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+ AVC_AUDIT_DATA_INIT(&ad, DEV);
+ ad.device = mfn;
+
+ rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad);
if ( rc )
return rc;
return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE,
- RESOURCE__USE, NULL);
+ RESOURCE__USE, &ad);
}
static int flask_perfcontrol(void)
@@ -753,6 +761,7 @@ static int ioport_has_perm(struct domain *d, uint32_t ioport, uint8_t access)
u32 rsid;
int rc = -EPERM;
+ struct avc_audit_data ad;
struct domain_security_struct *ssec, *tsec;
rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
@@ -773,13 +782,16 @@ static int ioport_has_perm(struct domain *d, uint32_t ioport, uint8_t access)
if ( rc )
return rc;
- rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+ AVC_AUDIT_DATA_INIT(&ad, DEV);
+ ad.device = ioport;
+
+ rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad);
if ( rc )
return rc;
if ( access )
return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE,
- RESOURCE__USE, NULL);
+ RESOURCE__USE, &ad);
else
return rc;
}
@@ -1081,6 +1093,7 @@ static int flask_assign_device(struct domain *d, uint32_t machine_bdf)
u32 rsid;
int rc = -EPERM;
struct domain_security_struct *ssec, *tsec;
+ struct avc_audit_data ad;
rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__ADD);
if ( rc )
@@ -1090,13 +1103,15 @@ static int flask_assign_device(struct domain *d, uint32_t machine_bdf)
if ( rc )
return rc;
+ AVC_AUDIT_DATA_INIT(&ad, DEV);
+ ad.device = (unsigned long) machine_bdf;
ssec = current->domain->ssid;
- rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__ADD_DEVICE, NULL);
+ rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__ADD_DEVICE, &ad);
if ( rc )
return rc;
tsec = d->ssid;
- return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, NULL);
+ return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
}
static int flask_deassign_device(struct domain *d, uint32_t machine_bdf)
diff --git a/xen/xsm/flask/include/avc.h b/xen/xsm/flask/include/avc.h
index d11ecff990..2168585373 100644
--- a/xen/xsm/flask/include/avc.h
+++ b/xen/xsm/flask/include/avc.h
@@ -38,11 +38,9 @@ struct sk_buff;
/* Auxiliary data to use in generating the audit record. */
struct avc_audit_data {
char type;
-#define AVC_AUDIT_DATA_FS 1
-#define AVC_AUDIT_DATA_NET 2
-#define AVC_AUDIT_DATA_CAP 3
-#define AVC_AUDIT_DATA_IPC 4
+#define AVC_AUDIT_DATA_DEV 1
struct domain *d;
+ unsigned long device;
};
#define v4info fam.v4
diff --git a/xen/xsm/flask/ss/policydb.c b/xen/xsm/flask/ss/policydb.c
index 33d422a936..ddbd9140a6 100644
--- a/xen/xsm/flask/ss/policydb.c
+++ b/xen/xsm/flask/ss/policydb.c
@@ -1773,10 +1773,13 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
}
policydb_str[len] = 0;
- if ( strcmp(policydb_str, POLICYDB_STRING) )
+ if ( strcmp(policydb_str, POLICYDB_STRING) == 0 )
+ p->target_type = TARGET_XEN;
+ else if ( strcmp(policydb_str, POLICYDB_STRING_OLD) == 0 )
+ p->target_type = TARGET_XEN_OLD;
+ else
{
- printk(KERN_ERR "Flask: policydb string %s does not match "
- "my string %s\n", policydb_str, POLICYDB_STRING);
+ printk(KERN_ERR "Flask: %s not a valid policydb string", policydb_str);
xfree(policydb_str);
goto bad;
}
@@ -1988,6 +1991,68 @@ int policydb_read(struct policydb *p, void *fp)
if ( rc )
goto bad;
break;
+ case OCON_PIRQ:
+ if ( p->target_type != TARGET_XEN )
+ {
+ printk(KERN_ERR
+ "Old xen policy does not support pirqcon");
+ goto bad;
+ }
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ c->u.pirq = le32_to_cpu(buf[0]);
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if ( rc )
+ goto bad;
+ break;
+ case OCON_IOPORT:
+ if ( p->target_type != TARGET_XEN )
+ {
+ printk(KERN_ERR
+ "Old xen policy does not support ioportcon");
+ goto bad;
+ }
+ rc = next_entry(buf, fp, sizeof(u32) *2);
+ if ( rc < 0 )
+ goto bad;
+ c->u.ioport.low_ioport = le32_to_cpu(buf[0]);
+ c->u.ioport.high_ioport = le32_to_cpu(buf[1]);
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if ( rc )
+ goto bad;
+ break;
+ case OCON_IOMEM:
+ if ( p->target_type != TARGET_XEN )
+ {
+ printk(KERN_ERR
+ "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]);
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if ( rc )
+ goto bad;
+ break;
+ case OCON_DEVICE:
+ if ( p->target_type != TARGET_XEN )
+ {
+ printk(KERN_ERR
+ "Old xen policy does not support pcidevicecon");
+ goto bad;
+ }
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ c->u.device = le32_to_cpu(buf[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");
diff --git a/xen/xsm/flask/ss/policydb.h b/xen/xsm/flask/ss/policydb.h
index 133f45e09f..d239f0e74b 100644
--- a/xen/xsm/flask/ss/policydb.h
+++ b/xen/xsm/flask/ss/policydb.h
@@ -147,10 +147,16 @@ struct cond_node;
struct ocontext {
union {
char *name; /* name of initial SID, fs, netif, fstype, path */
- int pirq;
- u32 ioport;
- unsigned long iomem;
+ u16 pirq;
u32 device;
+ struct {
+ u32 low_ioport;
+ u32 high_ioport;
+ } ioport;
+ struct {
+ u32 low_iomem;
+ u32 high_iomem;
+ } iomem;
} u;
struct context context[2]; /* security context(s) */
u32 sid[2]; /* SID(s) */
@@ -174,9 +180,7 @@ struct ocontext {
#define OCON_IOPORT 2 /* io ports */
#define OCON_IOMEM 3 /* io memory */
#define OCON_DEVICE 4 /* pci devices */
-#define OCON_DUMMY1 5 /* reserved */
-#define OCON_DUMMY2 6 /* reserved */
-#define OCON_NUM 7
+#define OCON_NUM 5
/* The policy database */
struct policydb {
@@ -239,6 +243,8 @@ struct policydb {
struct ebitmap permissive_map;
unsigned int policyvers;
+
+ u16 target_type;
};
extern void policydb_destroy(struct policydb *p);
@@ -257,7 +263,10 @@ extern int policydb_read(struct policydb *p, void *fp);
#define OBJECT_R_VAL 1
#define POLICYDB_MAGIC FLASK_MAGIC
-#define POLICYDB_STRING "SE Linux"
+#define POLICYDB_STRING "XenFlask"
+#define POLICYDB_STRING_OLD "SE Linux"
+#define TARGET_XEN 1
+#define TARGET_XEN_OLD 0
struct policy_file {
char *data;
diff --git a/xen/xsm/flask/ss/services.c b/xen/xsm/flask/ss/services.c
index f1cc36e48e..f841aa710e 100644
--- a/xen/xsm/flask/ss/services.c
+++ b/xen/xsm/flask/ss/services.c
@@ -1569,7 +1569,7 @@ int security_iomem_sid(unsigned long mfn, u32 *out_sid)
c = policydb.ocontexts[OCON_IOMEM];
while ( c )
{
- if ( c->u.iomem == mfn )
+ if ( c->u.iomem.low_iomem <= mfn && c->u.iomem.high_iomem >= mfn )
break;
c = c->next;
}
@@ -1609,7 +1609,8 @@ int security_ioport_sid(u32 ioport, u32 *out_sid)
c = policydb.ocontexts[OCON_IOPORT];
while ( c )
{
- if ( c->u.ioport == ioport )
+ if ( c->u.ioport.low_ioport <= ioport &&
+ c->u.ioport.high_ioport >= ioport )
break;
c = c->next;
}
@@ -1635,8 +1636,8 @@ out:
}
/**
- * security_ioport_sid - Obtain the SID for an ioport.
- * @ioport: ioport
+ * security_device_sid - Obtain the SID for a PCI device.
+ * @ioport: device
* @out_sid: security identifier
*/
int security_device_sid(u32 device, u32 *out_sid)