This is an RFC on one approach to supporting more than one "privileged"
domain in Xen in order to enable decomposition of dom0. This approach
allows the definition of privilege to be assigned through policy rather
than hardcoded. The expectation is that one would then use the other
policy-based controls to restrict precisely what can be done by the
privileged domain. This will likely require expanding the set of XSM
hooks to ensure full coverage of all privileged operations.
I know that others have implemented similar extensions or hacks to
IS_PRIV and/or IS_PRIV_FOR in order to provide similar functionality, so
hopefully this RFC will bring out all relevant parties and open up a
dialogue on how to do this in a uniform way.
This patch provides a simple policy-based mechanism for setting the
privilege state of a domain so that we can allow domains other than dom0
to invoke privileged hypercalls. The implementation approach in this
patch avoids any changes outside of the flask code. Upon domain
creation, within the existing xsm hook, we check a new 'ispriv'
permission on the domain ssid and if allowed by the policy, we set the
is_privileged flag for the domain.
An alternative implementation would be to replace the IS_PRIV()
definition with an XSM hook call similar to what we do for capable() in
Linux, but that would require a change to core xen and would turn
IS_PRIV() from a bit test into a function call, adding overhead on each
check.
To avoid granting privilege to all domains when in permissive mode, the
'ispriv' check is performed with the AVC_STRICT flag (ported from
SELinux) to ignore permissive mode. We also use the _noaudit interface
since the check is applied on every domain creation rather than when
there is an actual attempt to use privilege.
The class validation logic in the policy loader was changed to be more
forgiving of unknown classes/permissions so that if you boot with an
older policy that does not define the new permission, it will still load
the policy and just deny the unknown class/perms.
---
tools/flask/policy/policy/flask/Makefile | 4 ++--
tools/flask/policy/policy/flask/access_vectors | 1 +
tools/flask/policy/policy/modules/xen/xen.if | 1 +
xen/xsm/flask/avc.c | 7 +++++--
xen/xsm/flask/hooks.c | 4 ++++
xen/xsm/flask/include/av_perm_to_string.h | 1 +
xen/xsm/flask/include/av_permissions.h | 1 +
xen/xsm/flask/include/avc.h | 4 +++-
xen/xsm/flask/ss/services.c | 6 +++---
9 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/tools/flask/policy/policy/flask/Makefile
b/tools/flask/policy/policy/flask/Makefile
--- a/tools/flask/policy/policy/flask/Makefile
+++ b/tools/flask/policy/policy/flask/Makefile
@@ -2,7 +2,7 @@
LIBSEL ?= ../../libselinux
# flask needs to know where to export the kernel headers.
-LINUXDIR ?= ../../../linux-2.6
+XENDIR ?= ../../../../..
AWK = awk
@@ -30,7 +30,7 @@
install -m 644 class_to_string.h av_inherit.h common_perm_to_string.h
av_perm_to_string.h $(LIBSEL)/src
tokern: all
- install -m 644 $(ALL_H_FILES) $(LINUXDIR)/security/selinux/include
+ install -m 644 $(ALL_H_FILES) $(XENDIR)/xen/xsm/flask/include
install: all
diff --git a/tools/flask/policy/policy/flask/access_vectors
b/tools/flask/policy/policy/flask/access_vectors
--- a/tools/flask/policy/policy/flask/access_vectors
+++ b/tools/flask/policy/policy/flask/access_vectors
@@ -77,6 +77,7 @@
setextvcpucontext
getvcpuextstate
setvcpuextstate
+ ispriv
}
class hvm
diff --git a/tools/flask/policy/policy/modules/xen/xen.if
b/tools/flask/policy/policy/modules/xen/xen.if
--- a/tools/flask/policy/policy/modules/xen/xen.if
+++ b/tools/flask/policy/policy/modules/xen/xen.if
@@ -5,6 +5,7 @@
################################################################################
define(`create_domain', `
type $2, domain_type;
+ allow $1 self:domain ispriv;
allow $1 $2:domain {create max_vcpus setdomainmaxmem
setaddrsize getdomaininfo hypercall
setvcpucontext scheduler unpause
diff --git a/xen/xsm/flask/avc.c b/xen/xsm/flask/avc.c
--- a/xen/xsm/flask/avc.c
+++ b/xen/xsm/flask/avc.c
@@ -773,6 +773,7 @@
* should be released for the auditing.
*/
int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+ unsigned flags,
struct av_decision *in_avd)
{
struct avc_node *node;
@@ -809,7 +810,9 @@
if ( denied )
{
- if ( !flask_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE) )
+ if ( flags & AVC_STRICT )
+ rc = -EACCES;
+ else if ( !flask_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE) )
avc_update_node(AVC_CALLBACK_GRANT,requested,
ssid,tsid,tclass,avd->seqno);
else
@@ -843,7 +846,7 @@
struct av_decision avd;
int rc;
- rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd);
+ rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
return rc;
}
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -507,6 +507,10 @@
dsec1->create_sid = SECSID_NULL;
dsec2->create_sid = SECSID_NULL;
+ if (avc_has_perm_noaudit(dsec2->sid, dsec2->sid, SECCLASS_DOMAIN,
+ DOMAIN__ISPRIV, AVC_STRICT, NULL) == 0)
+ d->is_privileged = 1;
+
return rc;
}
diff --git a/xen/xsm/flask/include/av_perm_to_string.h
b/xen/xsm/flask/include/av_perm_to_string.h
--- a/xen/xsm/flask/include/av_perm_to_string.h
+++ b/xen/xsm/flask/include/av_perm_to_string.h
@@ -52,6 +52,7 @@
S_(SECCLASS_DOMAIN, DOMAIN__SETEXTVCPUCONTEXT, "setextvcpucontext")
S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUEXTSTATE, "getvcpuextstate")
S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUEXTSTATE, "setvcpuextstate")
+ S_(SECCLASS_DOMAIN, DOMAIN__ISPRIV, "ispriv")
S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc")
S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc")
S_(SECCLASS_HVM, HVM__SETPARAM, "setparam")
diff --git a/xen/xsm/flask/include/av_permissions.h
b/xen/xsm/flask/include/av_permissions.h
--- a/xen/xsm/flask/include/av_permissions.h
+++ b/xen/xsm/flask/include/av_permissions.h
@@ -53,6 +53,7 @@
#define DOMAIN__SETEXTVCPUCONTEXT 0x02000000UL
#define DOMAIN__GETVCPUEXTSTATE 0x04000000UL
#define DOMAIN__SETVCPUEXTSTATE 0x08000000UL
+#define DOMAIN__ISPRIV 0x10000000UL
#define HVM__SETHVMC 0x00000001UL
#define HVM__GETHVMC 0x00000002UL
diff --git a/xen/xsm/flask/include/avc.h b/xen/xsm/flask/include/avc.h
--- a/xen/xsm/flask/include/avc.h
+++ b/xen/xsm/flask/include/avc.h
@@ -73,8 +73,10 @@
void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct av_decision *avd, int result, struct avc_audit_data *auditdata);
+#define AVC_STRICT 1 /* Ignore permissive mode. */
int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
- struct av_decision *avd);
+ unsigned flags,
+ struct av_decision *avd);
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct avc_audit_data *auditdata);
diff --git a/xen/xsm/flask/ss/services.c b/xen/xsm/flask/ss/services.c
--- a/xen/xsm/flask/ss/services.c
+++ b/xen/xsm/flask/ss/services.c
@@ -1186,7 +1186,7 @@
printk(KERN_INFO
"Flask: class %s not defined in policy\n",
def_class);
- return -EINVAL;
+ continue;
}
pol_class = p->p_class_val_to_name[i-1];
if ( strcmp(pol_class, def_class) )
@@ -1214,7 +1214,7 @@
printk(KERN_INFO
"Flask: permission %s in class %s not defined in policy\n",
def_perm, pol_class);
- return -EINVAL;
+ continue;
}
perdatum = hashtab_search(perms->table, def_perm);
if ( perdatum == NULL )
@@ -1264,7 +1264,7 @@
printk(KERN_INFO
"Flask: permission %s in class %s not defined in policy\n",
def_perm, pol_class);
- return -EINVAL;
+ continue;
}
perdatum = hashtab_search(perms->table, def_perm);
if ( perdatum == NULL )
--
Stephen Smalley
National Security Agency
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|