selinux: introduce permissive types
authorEric Paris <eparis@redhat.com>
Mon, 31 Mar 2008 01:17:33 +0000 (12:17 +1100)
committerJames Morris <jmorris@namei.org>
Fri, 18 Apr 2008 10:26:11 +0000 (20:26 +1000)
Introduce the concept of a permissive type.  A new ebitmap is introduced to
the policy database which indicates if a given type has the permissive bit
set or not.  This bit is tested for the scontext of any denial.  The bit is
meaningless on types which only appear as the target of a decision and never
the source.  A domain running with a permissive type will be allowed to
perform any action similarly to when the system is globally set permissive.

Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
security/selinux/Kconfig
security/selinux/avc.c
security/selinux/include/security.h
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c

index 2b517d6186729c05608d56dd1123926a242c61d2..a436d1cfa88b8ef68fec2de2addf3af4cc2e54e3 100644 (file)
@@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
 config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
        int "NSA SELinux maximum supported policy format version value"
        depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
-       range 15 22
+       range 15 23
        default 19
        help
          This option sets the value for the maximum policy format version
index cb3f0ce0b00a374eddebada7539eebdf8e8747c0..a4fc6e6d038a0afe5bfc5044df2f8be42cbefc15 100644 (file)
@@ -893,12 +893,13 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
        denied = requested & ~(p_ae->avd.allowed);
 
        if (denied) {
-               if (selinux_enforcing || (flags & AVC_STRICT))
+               if (flags & AVC_STRICT)
                        rc = -EACCES;
+               else if (!selinux_enforcing || security_permissive_sid(ssid))
+                       avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
+                                       tsid, tclass);
                else
-                       if (node)
-                               avc_update_node(AVC_CALLBACK_GRANT,requested,
-                                               ssid,tsid,tclass);
+                       rc = -EACCES;
        }
 
        rcu_read_unlock();
index 315b4ec1e12aeef8b2e405f9cbf9bff66e8b980b..dd70aa084637d1b6387a69732f3ba682df9a4590 100644 (file)
 #define POLICYDB_VERSION_AVTAB         20
 #define POLICYDB_VERSION_RANGETRANS    21
 #define POLICYDB_VERSION_POLCAP                22
+#define POLICYDB_VERSION_PERMISSIVE    23
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
 #define POLICYDB_VERSION_MAX   CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
 #else
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_POLCAP
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_PERMISSIVE
 #endif
 
 #define CONTEXT_MNT    0x01
@@ -69,6 +70,8 @@ struct av_decision {
        u32 seqno;
 };
 
+int security_permissive_sid(u32 sid);
+
 int security_compute_av(u32 ssid, u32 tsid,
        u16 tclass, u32 requested,
        struct av_decision *avd);
index 325551cd7fc7c16570339eed2363eb945dcb8ad3..6bdb0ff6a927ce9da562188ceaced7a7dce21ad4 100644 (file)
@@ -111,6 +111,11 @@ static struct policydb_compat_info policydb_compat[] = {
                .version        = POLICYDB_VERSION_POLCAP,
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
+       },
+       {
+               .version        = POLICYDB_VERSION_PERMISSIVE,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
        }
 };
 
@@ -194,6 +199,7 @@ static int policydb_init(struct policydb *p)
                goto out_free_symtab;
 
        ebitmap_init(&p->policycaps);
+       ebitmap_init(&p->permissive_map);
 
 out:
        return rc;
@@ -687,6 +693,7 @@ void policydb_destroy(struct policydb *p)
        kfree(p->type_attr_map);
        kfree(p->undefined_perms);
        ebitmap_destroy(&p->policycaps);
+       ebitmap_destroy(&p->permissive_map);
 
        return;
 }
@@ -1570,6 +1577,10 @@ int policydb_read(struct policydb *p, void *fp)
            ebitmap_read(&p->policycaps, fp) != 0)
                goto bad;
 
+       if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+           ebitmap_read(&p->permissive_map, fp) != 0)
+               goto bad;
+
        info = policydb_lookup_compat(p->policyvers);
        if (!info) {
                printk(KERN_ERR "SELinux:  unable to find policy compat info "
index c4ce996e202c1c62357bdaf7bcd02d5988bb4fff..ba593a3da8775e9d3b18eea4802fc4c8466667a5 100644 (file)
@@ -243,6 +243,8 @@ struct policydb {
 
        struct ebitmap policycaps;
 
+       struct ebitmap permissive_map;
+
        unsigned int policyvers;
 
        unsigned int reject_unknown : 1;
index face5795c760ca529eadcd70c14c6c0c3adcca18..eefa89ce77a70edcfbce7aab17c475dbaa1d5c5c 100644 (file)
@@ -417,6 +417,31 @@ inval_class:
        return -EINVAL;
 }
 
+/*
+ * Given a sid find if the type has the permissive flag set
+ */
+int security_permissive_sid(u32 sid)
+{
+       struct context *context;
+       u32 type;
+       int rc;
+
+       POLICY_RDLOCK;
+
+       context = sidtab_search(&sidtab, sid);
+       BUG_ON(!context);
+
+       type = context->type;
+       /*
+        * we are intentionally using type here, not type-1, the 0th bit may
+        * someday indicate that we are globally setting permissive in policy.
+        */
+       rc = ebitmap_get_bit(&policydb.permissive_map, type);
+
+       POLICY_RDUNLOCK;
+       return rc;
+}
+
 static int security_validtrans_handle_fail(struct context *ocontext,
                                            struct context *ncontext,
                                            struct context *tcontext,