aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-10-27 12:52:57 +0000
committerKeir Fraser <keir.fraser@citrix.com>2009-10-27 12:52:57 +0000
commit78942912c8a3ff303b910d4a179ff6be7e9b0477 (patch)
tree10468e48843fbc769f0298b5bc52df3dfb63aa73
parent16d8dcbfb346174e67a61134a45d40870d112cad (diff)
downloadxen-78942912c8a3ff303b910d4a179ff6be7e9b0477.tar.gz
xen-78942912c8a3ff303b910d4a179ff6be7e9b0477.tar.bz2
xen-78942912c8a3ff303b910d4a179ff6be7e9b0477.zip
xsm: Add support for Xen device policies
Add support for Xen ocontext records to enable device polices. The default policy will not be changed and instructions have been added to enable the new functionality. Examples on how to use the new policy language have been added but commented out. The newest version of checkpolicy (>= 2.0.20) and libsepol (>= 2.0.39) is needed in order to compile it. Devices can be labeled and enforced using the following new commands; pirqcon, iomemcon, ioportcon and pcidevicecon. Signed-off-by : George Coker <gscoker@alpha.ncsc.mil> Signed-off-by : Paul Nuzzi <pjnuzzi@tycho.ncsc.mil>
-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)