selinux: Add IB Port SMP access vector
authorDaniel Jurgens <danielj@mellanox.com>
Fri, 19 May 2017 12:48:58 +0000 (15:48 +0300)
committerPaul Moore <paul@paul-moore.com>
Tue, 23 May 2017 16:28:02 +0000 (12:28 -0400)
Add a type for Infiniband ports and an access vector for subnet
management packets. Implement the ib_port_smp hook to check that the
caller has permission to send and receive SMPs on the end port specified
by the device name and port. Add interface to query the SID for a IB
port, which walks the IB_PORT ocontexts to find an entry for the
given name and port.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>
Reviewed-by: James Morris <james.l.morris@oracle.com>
Acked-by: Doug Ledford <dledford@redhat.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
include/linux/lsm_audit.h
security/lsm_audit.c
security/selinux/hooks.c
security/selinux/include/classmap.h
security/selinux/include/security.h
security/selinux/ss/services.c

index 0df5639a4ff430a8974ef0aa02bfd35c804d74d6..22b5d4e687ce0f3a3c2f226845390e5ca91b7385 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/path.h>
 #include <linux/key.h>
 #include <linux/skbuff.h>
+#include <rdma/ib_verbs.h>
 
 struct lsm_network_audit {
        int netif;
@@ -50,6 +51,11 @@ struct lsm_ibpkey_audit {
        u16     pkey;
 };
 
+struct lsm_ibendport_audit {
+       char    dev_name[IB_DEVICE_NAME_MAX];
+       u8      port;
+};
+
 /* Auxiliary data to use in generating the audit record. */
 struct common_audit_data {
        char type;
@@ -66,6 +72,7 @@ struct common_audit_data {
 #define LSM_AUDIT_DATA_IOCTL_OP        11
 #define LSM_AUDIT_DATA_FILE    12
 #define LSM_AUDIT_DATA_IBPKEY  13
+#define LSM_AUDIT_DATA_IBENDPORT 14
        union   {
                struct path path;
                struct dentry *dentry;
@@ -84,6 +91,7 @@ struct common_audit_data {
                struct lsm_ioctlop_audit *op;
                struct file *file;
                struct lsm_ibpkey_audit *ibpkey;
+               struct lsm_ibendport_audit *ibendport;
        } u;
        /* this union contains LSM specific data */
        union {
index c22c99fae06a7e70d3231fbef1499b2e6389aa98..28d4c3a528abce522c4c274c9233cfc03f3eadc2 100644 (file)
@@ -421,6 +421,11 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                                 a->u.ibpkey->pkey, &sbn_pfx);
                break;
        }
+       case LSM_AUDIT_DATA_IBENDPORT:
+               audit_log_format(ab, " device=%s port_num=%u",
+                                a->u.ibendport->dev_name,
+                                a->u.ibendport->port);
+               break;
        } /* switch (a->type) */
 }
 
index b59255f86274195a6e493ebcf313bc4644827fd8..91ec46dd34d9d60b30d4b294ab626ddf92a22e01 100644 (file)
@@ -6169,6 +6169,29 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
                            INFINIBAND_PKEY__ACCESS, &ad);
 }
 
+static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
+                                           u8 port_num)
+{
+       struct common_audit_data ad;
+       int err;
+       u32 sid = 0;
+       struct ib_security_struct *sec = ib_sec;
+       struct lsm_ibendport_audit ibendport;
+
+       err = security_ib_endport_sid(dev_name, port_num, &sid);
+
+       if (err)
+               return err;
+
+       ad.type = LSM_AUDIT_DATA_IBENDPORT;
+       strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name));
+       ibendport.port = port_num;
+       ad.u.ibendport = &ibendport;
+       return avc_has_perm(sec->sid, sid,
+                           SECCLASS_INFINIBAND_ENDPORT,
+                           INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
+}
+
 static int selinux_ib_alloc_security(void **ib_sec)
 {
        struct ib_security_struct *sec;
@@ -6374,6 +6397,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
 #ifdef CONFIG_SECURITY_INFINIBAND
        LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
+       LSM_HOOK_INIT(ib_endport_manage_subnet,
+                     selinux_ib_endport_manage_subnet),
        LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
        LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security),
 #endif
index 0fec1c505f844830b3f1e897f00af2ca0f90e25d..b9fe3434b036d8a0e7c55716753f04735c1a9a0e 100644 (file)
@@ -233,6 +233,8 @@ struct security_class_mapping secclass_map[] = {
          { COMMON_SOCK_PERMS, NULL } },
        { "infiniband_pkey",
          { "access", NULL } },
+       { "infiniband_endport",
+         { "manage_subnet", NULL } },
        { NULL }
   };
 
index 592c014e369c1ce2b5b11ee32216b4ca50652215..e91f08c16c0b2943686fe94eb3ac84b09078e5de 100644 (file)
@@ -183,6 +183,8 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid);
 
 int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid);
 
+int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid);
+
 int security_netif_sid(char *name, u32 *if_sid);
 
 int security_node_sid(u16 domain, void *addr, u32 addrlen,
index 02257d90adc921242d14a6462bbf9378083dcb4e..202166612b806d3636839992c13720a3081e426e 100644 (file)
@@ -2272,6 +2272,47 @@ out:
        return rc;
 }
 
+/**
+ * security_ib_endport_sid - Obtain the SID for a subnet management interface.
+ * @dev_name: device name
+ * @port: port number
+ * @out_sid: security identifier
+ */
+int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
+{
+       struct ocontext *c;
+       int rc = 0;
+
+       read_lock(&policy_rwlock);
+
+       c = policydb.ocontexts[OCON_IBENDPORT];
+       while (c) {
+               if (c->u.ibendport.port == port_num &&
+                   !strncmp(c->u.ibendport.dev_name,
+                            dev_name,
+                            IB_DEVICE_NAME_MAX))
+                       break;
+
+               c = c->next;
+       }
+
+       if (c) {
+               if (!c->sid[0]) {
+                       rc = sidtab_context_to_sid(&sidtab,
+                                                  &c->context[0],
+                                                  &c->sid[0]);
+                       if (rc)
+                               goto out;
+               }
+               *out_sid = c->sid[0];
+       } else
+               *out_sid = SECINITSID_UNLABELED;
+
+out:
+       read_unlock(&policy_rwlock);
+       return rc;
+}
+
 /**
  * security_netif_sid - Obtain the SID for a network interface.
  * @name: interface name