SELinux: Add a capabilities bitmap to SELinux policy version 22
authorPaul Moore <paul.moore@hp.com>
Tue, 29 Jan 2008 13:38:19 +0000 (08:38 -0500)
committerJames Morris <jmorris@namei.org>
Tue, 29 Jan 2008 21:17:23 +0000 (08:17 +1100)
Add a new policy capabilities bitmap to SELinux policy version 22.  This bitmap
will enable the security server to query the policy to determine which features
it supports.

Signed-off-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>
security/selinux/Kconfig
security/selinux/include/security.h
security/selinux/selinuxfs.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c

index b32a459c0683c720271b6ab15d0829b11ef3e125..2b517d6186729c05608d56dd1123926a242c61d2 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
 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 21
+       range 15 22
        default 19
        help
          This option sets the value for the maximum policy format version
        default 19
        help
          This option sets the value for the maximum policy format version
index a33437bba932214fb3a285f3b7c036ff269bef53..a22de97718065c4b406ca7130fde7d613a5f32e8 100644 (file)
 #define POLICYDB_VERSION_MLS           19
 #define POLICYDB_VERSION_AVTAB         20
 #define POLICYDB_VERSION_RANGETRANS    21
 #define POLICYDB_VERSION_MLS           19
 #define POLICYDB_VERSION_AVTAB         20
 #define POLICYDB_VERSION_RANGETRANS    21
+#define POLICYDB_VERSION_POLCAP                22
 
 /* 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
 
 /* 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_RANGETRANS
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_POLCAP
 #endif
 
 struct netlbl_lsm_secattr;
 #endif
 
 struct netlbl_lsm_secattr;
@@ -39,8 +40,19 @@ struct netlbl_lsm_secattr;
 extern int selinux_enabled;
 extern int selinux_mls_enabled;
 
 extern int selinux_enabled;
 extern int selinux_mls_enabled;
 
+/* Policy capabilities */
+enum {
+       POLICYDB_CAPABILITY_NETPEER,
+       __POLICYDB_CAPABILITY_MAX
+};
+#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
+
+extern int selinux_policycap_netpeer;
+
 int security_load_policy(void * data, size_t len);
 
 int security_load_policy(void * data, size_t len);
 
+int security_policycap_supported(unsigned int req_cap);
+
 #define SEL_VEC_MAX 32
 struct av_decision {
        u32 allowed;
 #define SEL_VEC_MAX 32
 struct av_decision {
        u32 allowed;
@@ -91,6 +103,7 @@ int security_get_classes(char ***classes, int *nclasses);
 int security_get_permissions(char *class, char ***perms, int *nperms);
 int security_get_reject_unknown(void);
 int security_get_allow_unknown(void);
 int security_get_permissions(char *class, char ***perms, int *nperms);
 int security_get_reject_unknown(void);
 int security_get_allow_unknown(void);
+int security_get_policycaps(int *len, int **values);
 
 #define SECURITY_FS_USE_XATTR          1 /* use xattr */
 #define SECURITY_FS_USE_TRANS          2 /* use transition SIDs, e.g. devpts/tmpfs */
 
 #define SECURITY_FS_USE_XATTR          1 /* use xattr */
 #define SECURITY_FS_USE_TRANS          2 /* use transition SIDs, e.g. devpts/tmpfs */
index 397fd4955fe1fb9dc9e57b95189084435f648294..a85740530afc676fdb777c88a8cb4136d90370cd 100644 (file)
@@ -2,6 +2,11 @@
  *
  *     Added conditional policy language extensions
  *
  *
  *     Added conditional policy language extensions
  *
+ *  Updated: Hewlett-Packard <paul.moore@hp.com>
+ *
+ *      Added support for the policy capability bitmap
+ *
+ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *     This program is free software; you can redistribute it and/or modify
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *     This program is free software; you can redistribute it and/or modify
 #include "objsec.h"
 #include "conditional.h"
 
 #include "objsec.h"
 #include "conditional.h"
 
+/* Policy capability filenames */
+static char *policycap_names[] = {
+       "network_peer_controls"
+};
+
 unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
 
 #ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
 unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
 
 #ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
@@ -72,6 +82,9 @@ static int *bool_pending_values = NULL;
 static struct dentry *class_dir = NULL;
 static unsigned long last_class_ino;
 
 static struct dentry *class_dir = NULL;
 static unsigned long last_class_ino;
 
+/* global data for policy capabilities */
+static struct dentry *policycap_dir = NULL;
+
 extern void selnl_notify_setenforce(int val);
 
 /* Check whether a task is allowed to use a security operation. */
 extern void selnl_notify_setenforce(int val);
 
 /* Check whether a task is allowed to use a security operation. */
@@ -111,10 +124,11 @@ enum sel_inos {
 
 static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
 
 
 static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
 
-#define SEL_INITCON_INO_OFFSET         0x01000000
-#define SEL_BOOL_INO_OFFSET    0x02000000
-#define SEL_CLASS_INO_OFFSET   0x04000000
-#define SEL_INO_MASK           0x00ffffff
+#define SEL_INITCON_INO_OFFSET         0x01000000
+#define SEL_BOOL_INO_OFFSET            0x02000000
+#define SEL_CLASS_INO_OFFSET           0x04000000
+#define SEL_POLICYCAP_INO_OFFSET       0x08000000
+#define SEL_INO_MASK                   0x00ffffff
 
 #define TMPBUFLEN      12
 static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
 
 #define TMPBUFLEN      12
 static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
@@ -263,6 +277,7 @@ static const struct file_operations sel_policyvers_ops = {
 /* declaration for sel_write_load */
 static int sel_make_bools(void);
 static int sel_make_classes(void);
 /* declaration for sel_write_load */
 static int sel_make_bools(void);
 static int sel_make_classes(void);
+static int sel_make_policycap(void);
 
 /* declaration for sel_make_class_dirs */
 static int sel_make_dir(struct inode *dir, struct dentry *dentry,
 
 /* declaration for sel_make_class_dirs */
 static int sel_make_dir(struct inode *dir, struct dentry *dentry,
@@ -323,6 +338,12 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
        }
 
        ret = sel_make_classes();
        }
 
        ret = sel_make_classes();
+       if (ret) {
+               length = ret;
+               goto out1;
+       }
+
+       ret = sel_make_policycap();
        if (ret)
                length = ret;
        else
        if (ret)
                length = ret;
        else
@@ -1399,6 +1420,24 @@ static const struct file_operations sel_perm_ops = {
        .read           = sel_read_perm,
 };
 
        .read           = sel_read_perm,
 };
 
+static ssize_t sel_read_policycap(struct file *file, char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       int value;
+       char tmpbuf[TMPBUFLEN];
+       ssize_t length;
+       unsigned long i_ino = file->f_path.dentry->d_inode->i_ino;
+
+       value = security_policycap_supported(i_ino & SEL_INO_MASK);
+       length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
+
+       return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+}
+
+static const struct file_operations sel_policycap_ops = {
+       .read           = sel_read_policycap,
+};
+
 static int sel_make_perm_files(char *objclass, int classvalue,
                                struct dentry *dir)
 {
 static int sel_make_perm_files(char *objclass, int classvalue,
                                struct dentry *dir)
 {
@@ -1545,6 +1584,36 @@ out:
        return rc;
 }
 
        return rc;
 }
 
+static int sel_make_policycap(void)
+{
+       unsigned int iter;
+       struct dentry *dentry = NULL;
+       struct inode *inode = NULL;
+
+       sel_remove_entries(policycap_dir);
+
+       for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
+               if (iter < ARRAY_SIZE(policycap_names))
+                       dentry = d_alloc_name(policycap_dir,
+                                             policycap_names[iter]);
+               else
+                       dentry = d_alloc_name(policycap_dir, "unknown");
+
+               if (dentry == NULL)
+                       return -ENOMEM;
+
+               inode = sel_make_inode(policycap_dir->d_sb, S_IFREG | S_IRUGO);
+               if (inode == NULL)
+                       return -ENOMEM;
+
+               inode->i_fop = &sel_policycap_ops;
+               inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET;
+               d_add(dentry, inode);
+       }
+
+       return 0;
+}
+
 static int sel_make_dir(struct inode *dir, struct dentry *dentry,
                        unsigned long *ino)
 {
 static int sel_make_dir(struct inode *dir, struct dentry *dentry,
                        unsigned long *ino)
 {
@@ -1673,6 +1742,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
 
        class_dir = dentry;
 
 
        class_dir = dentry;
 
+       dentry = d_alloc_name(sb->s_root, "policy_capabilities");
+       if (!dentry) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
+       if (ret)
+               goto err;
+
+       policycap_dir = dentry;
+
 out:
        return ret;
 err:
 out:
        return ret;
 err:
index b582aae3c62c339f320a11d067a14f53fdea3038..bd7d6a00342daa1a36ffcd244e0ac2eb02fdab79 100644 (file)
  *
  *     Added conditional policy language extensions
  *
  *
  *     Added conditional policy language extensions
  *
+ * Updated: Hewlett-Packard <paul.moore@hp.com>
+ *
+ *      Added support for the policy capability bitmap
+ *
+ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  *     This program is free software; you can redistribute it and/or modify
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  *     This program is free software; you can redistribute it and/or modify
@@ -102,6 +107,11 @@ static struct policydb_compat_info policydb_compat[] = {
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
        },
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
        },
+       {
+               .version        = POLICYDB_VERSION_POLCAP,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
+       }
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -183,6 +193,8 @@ static int policydb_init(struct policydb *p)
        if (rc)
                goto out_free_symtab;
 
        if (rc)
                goto out_free_symtab;
 
+       ebitmap_init(&p->policycaps);
+
 out:
        return rc;
 
 out:
        return rc;
 
@@ -673,8 +685,8 @@ void policydb_destroy(struct policydb *p)
                        ebitmap_destroy(&p->type_attr_map[i]);
        }
        kfree(p->type_attr_map);
                        ebitmap_destroy(&p->type_attr_map[i]);
        }
        kfree(p->type_attr_map);
-
        kfree(p->undefined_perms);
        kfree(p->undefined_perms);
+       ebitmap_destroy(&p->policycaps);
 
        return;
 }
 
        return;
 }
@@ -1554,6 +1566,10 @@ int policydb_read(struct policydb *p, void *fp)
        p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
        p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
 
        p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
        p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
 
+       if (p->policyvers >= POLICYDB_VERSION_POLCAP &&
+           ebitmap_read(&p->policycaps, fp) != 0)
+               goto bad;
+
        info = policydb_lookup_compat(p->policyvers);
        if (!info) {
                printk(KERN_ERR "security:  unable to find policy compat info "
        info = policydb_lookup_compat(p->policyvers);
        if (!info) {
                printk(KERN_ERR "security:  unable to find policy compat info "
index ed6fc687c66fd44107afe0e475ab233399e2d0d2..c4ce996e202c1c62357bdaf7bcd02d5988bb4fff 100644 (file)
@@ -241,6 +241,8 @@ struct policydb {
        /* type -> attribute reverse mapping */
        struct ebitmap *type_attr_map;
 
        /* type -> attribute reverse mapping */
        struct ebitmap *type_attr_map;
 
+       struct ebitmap policycaps;
+
        unsigned int policyvers;
 
        unsigned int reject_unknown : 1;
        unsigned int policyvers;
 
        unsigned int reject_unknown : 1;
index 8dfaa3e7c26dacdf0e7de2756d82cdd277d80f97..8ee04a424df7c31d5b62558e8a7796ecdb909e93 100644 (file)
  * Updated: Hewlett-Packard <paul.moore@hp.com>
  *
  *      Added support for NetLabel
  * Updated: Hewlett-Packard <paul.moore@hp.com>
  *
  *      Added support for NetLabel
+ *      Added support for the policy capability bitmap
  *
  * Updated: Chad Sellers <csellers@tresys.com>
  *
  *  Added validation of kernel classes and permissions
  *
  *
  * Updated: Chad Sellers <csellers@tresys.com>
  *
  *  Added validation of kernel classes and permissions
  *
- * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@@ -59,6 +60,8 @@
 extern void selnl_notify_policyload(u32 seqno);
 unsigned int policydb_loaded_version;
 
 extern void selnl_notify_policyload(u32 seqno);
 unsigned int policydb_loaded_version;
 
+int selinux_policycap_netpeer;
+
 /*
  * This is declared in avc.c
  */
 /*
  * This is declared in avc.c
  */
@@ -1299,6 +1302,12 @@ bad:
        goto out;
 }
 
        goto out;
 }
 
+static void security_load_policycaps(void)
+{
+       selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
+                                                 POLICYDB_CAPABILITY_NETPEER);
+}
+
 extern void selinux_complete_init(void);
 static int security_preserve_bools(struct policydb *p);
 
 extern void selinux_complete_init(void);
 static int security_preserve_bools(struct policydb *p);
 
@@ -1346,6 +1355,7 @@ int security_load_policy(void *data, size_t len)
                        avtab_cache_destroy();
                        return -EINVAL;
                }
                        avtab_cache_destroy();
                        return -EINVAL;
                }
+               security_load_policycaps();
                policydb_loaded_version = policydb.policyvers;
                ss_initialized = 1;
                seqno = ++latest_granting;
                policydb_loaded_version = policydb.policyvers;
                ss_initialized = 1;
                seqno = ++latest_granting;
@@ -1404,6 +1414,7 @@ int security_load_policy(void *data, size_t len)
        POLICY_WRLOCK;
        memcpy(&policydb, &newpolicydb, sizeof policydb);
        sidtab_set(&sidtab, &newsidtab);
        POLICY_WRLOCK;
        memcpy(&policydb, &newpolicydb, sizeof policydb);
        sidtab_set(&sidtab, &newsidtab);
+       security_load_policycaps();
        seqno = ++latest_granting;
        policydb_loaded_version = policydb.policyvers;
        POLICY_WRUNLOCK;
        seqno = ++latest_granting;
        policydb_loaded_version = policydb.policyvers;
        POLICY_WRUNLOCK;
@@ -2148,6 +2159,60 @@ int security_get_allow_unknown(void)
        return policydb.allow_unknown;
 }
 
        return policydb.allow_unknown;
 }
 
+/**
+ * security_get_policycaps - Query the loaded policy for its capabilities
+ * @len: the number of capability bits
+ * @values: the capability bit array
+ *
+ * Description:
+ * Get an array of the policy capabilities in @values where each entry in
+ * @values is either true (1) or false (0) depending the policy's support of
+ * that feature.  The policy capabilities are defined by the
+ * POLICYDB_CAPABILITY_* enums.  The size of the array is stored in @len and it
+ * is up to the caller to free the array in @values.  Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int security_get_policycaps(int *len, int **values)
+{
+       int rc = -ENOMEM;
+       unsigned int iter;
+
+       POLICY_RDLOCK;
+
+       *values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
+       if (*values == NULL)
+               goto out;
+       for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
+               (*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
+       *len = POLICYDB_CAPABILITY_MAX;
+
+out:
+       POLICY_RDUNLOCK;
+       return rc;
+}
+
+/**
+ * security_policycap_supported - Check for a specific policy capability
+ * @req_cap: capability
+ *
+ * Description:
+ * This function queries the currently loaded policy to see if it supports the
+ * capability specified by @req_cap.  Returns true (1) if the capability is
+ * supported, false (0) if it isn't supported.
+ *
+ */
+int security_policycap_supported(unsigned int req_cap)
+{
+       int rc;
+
+       POLICY_RDLOCK;
+       rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
+       POLICY_RDUNLOCK;
+
+       return rc;
+}
+
 struct selinux_audit_rule {
        u32 au_seqno;
        struct context au_ctxt;
 struct selinux_audit_rule {
        u32 au_seqno;
        struct context au_ctxt;