[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC][PATCH] xen/xsm/flask: Policy based setting of is_privileged


  • To: Xen <xen-devel@xxxxxxxxxxxxxxxxxxx>
  • From: Stephen Smalley <sds@xxxxxxxxxxxxx>
  • Date: Tue, 22 Mar 2011 11:11:12 -0400
  • Delivery-date: Tue, 22 Mar 2011 08:12:10 -0700
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.