All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] SELinux user space support for Infiniband RDMA
@ 2017-05-18 22:25 Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 1/9] checkpolicy: Add support for ibpkeycon labels Dan Jurgens
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Infiniband applications access HW from user-space -- traffic is generated
directly by HW, bypassing the kernel. Consequently, Infiniband Partitions,
which are associated directly with HW transport endpoints, are a natural
choice for enforcing granular mandatory access control for Infiniband. QPs
may only send or receives packets tagged with the corresponding partition
key (PKey). The PKey is not a cryptographic key; it's a 16 bit number
identifying the partition.

Every Infiniband fabric is controlled by a central Subnet Manager (SM).
The SM provisions the partitions by assigning each port with the
partitions it can access. In addition, the SM tags each port with a subnet
prefix, which identifies the subnet. Determining which users are allowed
to access which partition keys on a given subnet forms an effective policy
for isolating users on the fabric. Any application that attempts to send
traffic on a given subnet is automatically subject to the policy,
regardless of which device and port it uses. SM software configures the
subnet through a privileged Subnet Management Interface (SMI), which is
presented by each Infiniband port. Thus, the SMI must also be controlled
to prevent unauthorized changes to fabric configuration and partitioning. 

To support access control for IB partitions and subnet management,
security contexts must be provided for two new types of objects - PKeys
and IB end ports.

A PKey label consists of a subnet prefix and a range of PKey values and is
similar to the labeling mechanism for netports. Each Infiniband port can
reside on a different subnet. So labeling the PKey values for specific
subnet prefixes provides the user maximum flexibility, as PKey values may
be determined independently for different subnets. There is a single
access vector for PKeys called "access".

An Infiniband port is labeled by device name and port number. There is a
single access vector for IB end ports called "manage_subnet".

This series adds support for parsing the new labeling mechanisms and
generating the policy. It also adds support for runtime labling of PKeys
and IB end ports via semanage.

This series is quite large, but most of the code is very similar to
existing code for the other *con labels.

Example label syntax:
ibpkeycon fe80:: 0xFFFF gen_context(system_u:object_r:default_ibpkey_t,s0)
ibpkeycon fe80:: 0-0x10 gen_context(system_u:object_r:public_ibpkey_t,s0)

ibendportcon mlx5_0 1 gen_context(system_u:object_r:opensm_ibendport_t,s0)

Example semanage commands:
semanage ibpkey -l
semanage ibpkey -a -t default_ibpkey_t -x fe80:: 0x8FFF
semanage ibpkey -D

semanage ibendport -l
semanage ibendport -a -t opensm_ibendport_t -z mlx4_0 2
semanage ibenpdort -d -z mlx4_0 2

---
v1:
- Fixed seobject ibpkey delete all name bug (pkey vs ibpkey).

Stephen Smalley:
- Always use s6_addr vs s6_addr32, remove DARWIN #ifdefs.
- Removed unused parameters from new sepol_*_sid functions.
- Got rid of variable length subnet prefix handling, it never varied. 

James Carter:
- Add kernel_to_cil and kernel_to_conf implementations for new OCONs.

Jason Zaman:
- Use SETools directly to query types by attribute in seobject.py.


- See individual patches for more detailed changes.

v2:
- Rebased over Stephens MOD_VERSION change.

Stephen Smalley:
- Bound check new ocontext fields
- Only store 8 bytes of subnet prefix in binary policy
- Make it so semanage doesn't crash if ipbkey_type or ibendport_type are
  undefined.
- Don't define INET6_ADDRLEN, use sizeof(struct in6_addr)

James Carter:
- Sort new ocontexts in kernel_to_common.c

- Additional smaller changes noted in specific patches.

Daniel Jurgens (9):
  checkpolicy: Add support for ibpkeycon labels
  libsepol: Add ibpkey ocontext handling
  libsepol: Add Infiniband Pkey handling to CIL
  checkpolicy: Add support for ibendportcon labels
  libsepol: Add ibendport ocontext handling
  libsepol: Add IB end port handling to CIL
  semanage: Update semanage to allow runtime labeling of Infiniband
    Pkeys
  semanage: Update semanage to allow runtime labeling of ibendports
  semanage: Update man pages for infiniband

 checkpolicy/checkpolicy.c                        |  47 +++
 checkpolicy/policy_define.c                      | 187 +++++++++
 checkpolicy/policy_define.h                      |   2 +
 checkpolicy/policy_parse.y                       |  27 +-
 checkpolicy/policy_scan.l                        |   5 +
 libsemanage/include/semanage/ibendport_record.h  |  62 +++
 libsemanage/include/semanage/ibendports_local.h  |  36 ++
 libsemanage/include/semanage/ibendports_policy.h |  28 ++
 libsemanage/include/semanage/ibpkey_record.h     |  74 ++++
 libsemanage/include/semanage/ibpkeys_local.h     |  36 ++
 libsemanage/include/semanage/ibpkeys_policy.h    |  28 ++
 libsemanage/include/semanage/semanage.h          |   6 +
 libsemanage/src/direct_api.c                     |  57 ++-
 libsemanage/src/handle.h                         |  50 ++-
 libsemanage/src/ibendport_internal.h             |  48 +++
 libsemanage/src/ibendport_record.c               | 154 +++++++
 libsemanage/src/ibendports_file.c                | 157 +++++++
 libsemanage/src/ibendports_local.c               | 153 +++++++
 libsemanage/src/ibendports_policy.c              |  55 +++
 libsemanage/src/ibendports_policydb.c            |  62 +++
 libsemanage/src/ibpkey_internal.h                |  52 +++
 libsemanage/src/ibpkey_record.c                  | 185 +++++++++
 libsemanage/src/ibpkeys_file.c                   | 181 +++++++++
 libsemanage/src/ibpkeys_local.c                  | 179 ++++++++
 libsemanage/src/ibpkeys_policy.c                 |  52 +++
 libsemanage/src/ibpkeys_policydb.c               |  62 +++
 libsemanage/src/libsemanage.map                  |   2 +
 libsemanage/src/policy_components.c              |   9 +-
 libsemanage/src/semanage_store.c                 |   2 +
 libsemanage/src/semanage_store.h                 |   2 +
 libsemanage/src/semanageswig.i                   |   6 +
 libsemanage/src/semanageswig_python.i            |  86 ++++
 libsemanage/utils/semanage_migrate_store         |   4 +-
 libsepol/cil/src/cil.c                           |  37 ++
 libsepol/cil/src/cil_binary.c                    |  68 ++++
 libsepol/cil/src/cil_binary.h                    |  24 ++
 libsepol/cil/src/cil_build_ast.c                 | 151 +++++++
 libsepol/cil/src/cil_build_ast.h                 |   4 +
 libsepol/cil/src/cil_copy_ast.c                  |  51 +++
 libsepol/cil/src/cil_copy_ast.h                  |   1 +
 libsepol/cil/src/cil_flavor.h                    |   2 +
 libsepol/cil/src/cil_internal.h                  |  20 +
 libsepol/cil/src/cil_policy.c                    |  31 ++
 libsepol/cil/src/cil_post.c                      |  87 ++++
 libsepol/cil/src/cil_post.h                      |   2 +
 libsepol/cil/src/cil_reset_ast.c                 |  19 +
 libsepol/cil/src/cil_resolve_ast.c               |  55 +++
 libsepol/cil/src/cil_resolve_ast.h               |   2 +
 libsepol/cil/src/cil_tree.c                      |  29 +-
 libsepol/cil/src/cil_verify.c                    |  46 +++
 libsepol/include/sepol/ibendport_record.h        |  68 ++++
 libsepol/include/sepol/ibendports.h              |  45 +++
 libsepol/include/sepol/ibpkey_record.h           |  77 ++++
 libsepol/include/sepol/ibpkeys.h                 |  44 ++
 libsepol/include/sepol/policydb/policydb.h       |  37 +-
 libsepol/include/sepol/policydb/services.h       |  16 +
 libsepol/include/sepol/sepol.h                   |   4 +
 libsepol/src/expand.c                            |  15 +
 libsepol/src/ibendport_internal.h                |  18 +
 libsepol/src/ibendport_record.c                  | 298 ++++++++++++++
 libsepol/src/ibendports.c                        | 255 ++++++++++++
 libsepol/src/ibpkey_internal.h                   |  21 +
 libsepol/src/ibpkey_record.c                     | 445 ++++++++++++++++++++
 libsepol/src/ibpkeys.c                           | 269 ++++++++++++
 libsepol/src/kernel_to_cil.c                     | 104 +++++
 libsepol/src/kernel_to_common.c                  |  37 ++
 libsepol/src/kernel_to_conf.c                    | 104 +++++
 libsepol/src/libsepol.map.in                     |   2 +
 libsepol/src/module_to_cil.c                     |  55 +++
 libsepol/src/policydb.c                          |  59 ++-
 libsepol/src/services.c                          |  74 ++++
 libsepol/src/write.c                             |  30 ++
 python/semanage/semanage                         | 116 +++++-
 python/semanage/semanage-ibendport.8             |  66 +++
 python/semanage/semanage-ibpkey.8                |  66 +++
 python/semanage/semanage.8                       |  16 +-
 python/semanage/seobject.py                      | 494 +++++++++++++++++++++++
 77 files changed, 5524 insertions(+), 36 deletions(-)
 create mode 100644 libsemanage/include/semanage/ibendport_record.h
 create mode 100644 libsemanage/include/semanage/ibendports_local.h
 create mode 100644 libsemanage/include/semanage/ibendports_policy.h
 create mode 100644 libsemanage/include/semanage/ibpkey_record.h
 create mode 100644 libsemanage/include/semanage/ibpkeys_local.h
 create mode 100644 libsemanage/include/semanage/ibpkeys_policy.h
 create mode 100644 libsemanage/src/ibendport_internal.h
 create mode 100644 libsemanage/src/ibendport_record.c
 create mode 100644 libsemanage/src/ibendports_file.c
 create mode 100644 libsemanage/src/ibendports_local.c
 create mode 100644 libsemanage/src/ibendports_policy.c
 create mode 100644 libsemanage/src/ibendports_policydb.c
 create mode 100644 libsemanage/src/ibpkey_internal.h
 create mode 100644 libsemanage/src/ibpkey_record.c
 create mode 100644 libsemanage/src/ibpkeys_file.c
 create mode 100644 libsemanage/src/ibpkeys_local.c
 create mode 100644 libsemanage/src/ibpkeys_policy.c
 create mode 100644 libsemanage/src/ibpkeys_policydb.c
 create mode 100644 libsepol/include/sepol/ibendport_record.h
 create mode 100644 libsepol/include/sepol/ibendports.h
 create mode 100644 libsepol/include/sepol/ibpkey_record.h
 create mode 100644 libsepol/include/sepol/ibpkeys.h
 create mode 100644 libsepol/src/ibendport_internal.h
 create mode 100644 libsepol/src/ibendport_record.c
 create mode 100644 libsepol/src/ibendports.c
 create mode 100644 libsepol/src/ibpkey_internal.h
 create mode 100644 libsepol/src/ibpkey_record.c
 create mode 100644 libsepol/src/ibpkeys.c
 create mode 100644 python/semanage/semanage-ibendport.8
 create mode 100644 python/semanage/semanage-ibpkey.8

-- 
2.12.2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/9] checkpolicy: Add support for ibpkeycon labels
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 2/9] libsepol: Add ibpkey ocontext handling Dan Jurgens
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Add checkpolicy support for scanning and parsing ibpkeycon labels. Also
create a new ocontext for Infiniband Pkeys and define a new policydb
version for infiniband support.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>

---
v1:
Stephen Smalley:
- Always use s6_addr instead of s6_addr32.
- Add comment about POLICYDB_VERSION_INFINIBAND being linux specific.

v2:
Stephen Smalley:
- Store subnet_prefix as 8 bytes.
---
 checkpolicy/policy_define.c                | 107 +++++++++++++++++++++++++++++
 checkpolicy/policy_define.h                |   1 +
 checkpolicy/policy_parse.y                 |  15 +++-
 checkpolicy/policy_scan.l                  |   3 +
 libsepol/include/sepol/policydb/policydb.h |  30 +++++---
 5 files changed, 144 insertions(+), 12 deletions(-)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index 8fab214b..e73ec8f7 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -20,6 +20,7 @@
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2008 Tresys Technology, LLC
  * Copyright (C) 2007 Red Hat Inc.
+ * Copyright (C) 2017 Mellanox Techonologies Inc.
  *	This program is free software; you can redistribute it and/or modify
  *  	it under the terms of the GNU General Public License as published by
  *	the Free Software Foundation, version 2.
@@ -5057,6 +5058,112 @@ int define_port_context(unsigned int low, unsigned int high)
 	return -1;
 }
 
+int define_ibpkey_context(unsigned int low, unsigned int high)
+{
+	ocontext_t *newc, *c, *l, *head;
+	struct in6_addr subnet_prefix;
+	char *id;
+	int rc = 0;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("ibpkeycon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		id = (char *)queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	newc = malloc(sizeof(*newc));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(*newc));
+
+	id = queue_remove(id_queue);
+	if (!id) {
+		yyerror("failed to read the subnet prefix");
+		rc = -1;
+		goto out;
+	}
+
+	rc = inet_pton(AF_INET6, id, &subnet_prefix);
+	free(id);
+	if (rc < 1) {
+		yyerror("failed to parse the subnet prefix");
+		if (rc == 0)
+			rc = -1;
+		goto out;
+	}
+
+	if (subnet_prefix.s6_addr[2] || subnet_prefix.s6_addr[3]) {
+		yyerror("subnet prefix should be 0's in the low order 64 bits.");
+		rc = -1;
+		goto out;
+	}
+
+	if (low > 0xffff || high > 0xffff) {
+		yyerror("pkey value too large, pkeys are 16 bits.");
+		rc = -1;
+		goto out;
+	}
+
+	memcpy(&newc->u.ibpkey.subnet_prefix, &subnet_prefix.s6_addr[0],
+	       sizeof(newc->u.ibpkey.subnet_prefix));
+
+	newc->u.ibpkey.low_pkey = low;
+	newc->u.ibpkey.high_pkey = high;
+
+	if (low > high) {
+		yyerror2("low pkey %d exceeds high pkey %d", low, high);
+		rc = -1;
+		goto out;
+	}
+
+	rc = parse_security_context(&newc->context[0]);
+	if (rc)
+		goto out;
+
+	/* Preserve the matching order specified in the configuration. */
+	head = policydbp->ocontexts[OCON_IBPKEY];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		unsigned int low2, high2;
+
+		low2 = c->u.ibpkey.low_pkey;
+		high2 = c->u.ibpkey.high_pkey;
+
+		if (low == low2 && high == high2 &&
+		    c->u.ibpkey.subnet_prefix == newc->u.ibpkey.subnet_prefix) {
+			yyerror2("duplicate ibpkeycon entry for %d-%d ",
+				 low, high);
+			rc = -1;
+			goto out;
+		}
+		if (low2 <= low && high2 >= high &&
+		    c->u.ibpkey.subnet_prefix == newc->u.ibpkey.subnet_prefix) {
+			yyerror2("ibpkeycon entry for %d-%d hidden by earlier entry for %d-%d",
+				 low, high, low2, high2);
+			rc = -1;
+			goto out;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_IBPKEY] = newc;
+
+	return 0;
+
+out:
+	free(newc);
+	return rc;
+}
+
 int define_netif_context(void)
 {
 	ocontext_t *newc, *c, *head;
diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
index 9f4b6d0d..75e3683b 100644
--- a/checkpolicy/policy_define.h
+++ b/checkpolicy/policy_define.h
@@ -43,6 +43,7 @@ int define_level(void);
 int define_netif_context(void);
 int define_permissive(void);
 int define_polcap(void);
+int define_ibpkey_context(unsigned int low, unsigned int high);
 int define_port_context(unsigned int low, unsigned int high);
 int define_pirq_context(unsigned int pirq);
 int define_iomem_context(uint64_t low, uint64_t high);
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
index 1ac1c96b..35b433bd 100644
--- a/checkpolicy/policy_parse.y
+++ b/checkpolicy/policy_parse.y
@@ -21,6 +21,7 @@
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2008 Tresys Technology, LLC
  * Copyright (C) 2007 Red Hat Inc.
+ * Copyright (C) 2017 Mellanox Technologies Inc.
  *	This program is free software; you can redistribute it and/or modify
  *  	it under the terms of the GNU General Public License as published by
  *	the Free Software Foundation, version 2.
@@ -135,6 +136,7 @@ typedef int (* require_func_t)(int pass);
 %token TARGET
 %token SAMEUSER
 %token FSCON PORTCON NETIFCON NODECON 
+%token IBPKEYCON
 %token PIRQCON IOMEMCON IOPORTCON PCIDEVICECON DEVICETREECON
 %token FSUSEXATTR FSUSETASK FSUSETRANS
 %token GENFSCON
@@ -170,7 +172,7 @@ base_policy             : { if (define_policy(pass, 0) == -1) return -1; }
 			  opt_default_rules opt_mls te_rbac users opt_constraints 
                          { if (pass == 1) { if (policydb_index_bools(policydbp)) return -1;}
 			   else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1;}}
-			  initial_sid_contexts opt_fs_contexts opt_fs_uses opt_genfs_contexts net_contexts opt_dev_contexts
+			  initial_sid_contexts opt_fs_contexts opt_fs_uses opt_genfs_contexts net_contexts opt_dev_contexts opt_ibpkey_contexts
 			;
 classes			: class_def 
 			| classes class_def
@@ -713,6 +715,17 @@ port_context_def	: PORTCON identifier number security_context_def
 			| PORTCON identifier number '-' number security_context_def
 			{if (define_port_context($3,$5)) return -1;}
 			;
+opt_ibpkey_contexts     : ibpkey_contexts
+                        |
+                        ;
+ibpkey_contexts		: ibpkey_context_def
+			| ibpkey_contexts ibpkey_context_def
+			;
+ibpkey_context_def	: IBPKEYCON ipv6_addr number security_context_def
+			{if (define_ibpkey_context($3,$3)) return -1;}
+			| IBPKEYCON ipv6_addr number '-' number security_context_def
+			{if (define_ibpkey_context($3,$5)) return -1;}
+			;
 opt_netif_contexts      : netif_contexts 
                         |
                         ;
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index 028bd25e..f742939a 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -12,6 +12,7 @@
  *	Added support for binary policy modules
  *
  * Copyright (C) 2003-5 Tresys Technology, LLC
+ * Copyright (C) 2017 Mellanox Technologies Inc.
  *	This program is free software; you can redistribute it and/or modify
  *  	it under the terms of the GNU General Public License as published by
  *	the Free Software Foundation, version 2.
@@ -183,6 +184,8 @@ INCOMP |
 incomp				{ return(INCOMP);}
 fscon |
 FSCON                           { return(FSCON);}
+ibpkeycon |
+IBPKEYCON			{ return(IBPKEYCON);}
 portcon |
 PORTCON				{ return(PORTCON);}
 netifcon |                     
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index 99e49902..d06d2153 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -24,6 +24,7 @@
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ * Copyright (C) 2017 Mellanox Techonolgies Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -358,6 +359,11 @@ typedef struct ocontext {
 			uint32_t low_ioport;
 			uint32_t high_ioport;
 		} ioport;
+		struct {
+			uint64_t subnet_prefix;
+			uint16_t low_pkey;
+			uint16_t high_pkey;
+		} ibpkey;
 	} u;
 	union {
 		uint32_t sclass;	/* security class for genfs */
@@ -386,14 +392,14 @@ typedef struct genfs {
 #define SYM_NUM     8
 
 /* object context array indices */
-#define OCON_ISID  0		/* initial SIDs */
-#define OCON_FS    1		/* unlabeled file systems */
-#define OCON_PORT  2		/* TCP and UDP port numbers */
-#define OCON_NETIF 3		/* network interfaces */
-#define OCON_NODE  4		/* nodes */
-#define OCON_FSUSE 5		/* fs_use */
-#define OCON_NODE6 6		/* IPv6 nodes */
-#define OCON_GENFS 7            /* needed for ocontext_supported */
+#define OCON_ISID  0	/* initial SIDs */
+#define OCON_FS    1	/* unlabeled file systems */
+#define OCON_PORT  2	/* TCP and UDP port numbers */
+#define OCON_NETIF 3	/* network interfaces */
+#define OCON_NODE  4	/* nodes */
+#define OCON_FSUSE 5	/* fs_use */
+#define OCON_NODE6 6	/* IPv6 nodes */
+#define OCON_IBPKEY 7	/* Infiniband PKEY */
 
 /* object context array indices for Xen */
 #define OCON_XEN_ISID  	    0    /* initial SIDs */
@@ -404,7 +410,7 @@ typedef struct genfs {
 #define OCON_XEN_DEVICETREE 5    /* device tree node */
 
 /* OCON_NUM needs to be the largest index in any platform's ocontext array */
-#define OCON_NUM   7
+#define OCON_NUM   8
 
 /* section: module information */
 
@@ -726,10 +732,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
 #define POLICYDB_VERSION_CONSTRAINT_NAMES	29
 #define POLICYDB_VERSION_XEN_DEVICETREE		30 /* Xen-specific */
 #define POLICYDB_VERSION_XPERMS_IOCTL	30 /* Linux-specific */
+#define POLICYDB_VERSION_INFINIBAND		31 /* Linux-specific */
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_XPERMS_IOCTL
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_INFINIBAND
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE		4
@@ -749,9 +756,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
 #define MOD_POLICYDB_VERSION_DEFAULT_TYPE	16
 #define MOD_POLICYDB_VERSION_CONSTRAINT_NAMES  17
 #define MOD_POLICYDB_VERSION_XPERMS_IOCTL  18
+#define MOD_POLICYDB_VERSION_INFINIBAND		19
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_XPERMS_IOCTL
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_INFINIBAND
 
 #define POLICYDB_CONFIG_MLS    1
 
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/9] libsepol: Add ibpkey ocontext handling
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 1/9] checkpolicy: Add support for ibpkeycon labels Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 3/9] libsepol: Add Infiniband Pkey handling to CIL Dan Jurgens
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Add support for reading, writing, and copying Infiniband Pkey ocontext
data. Also add support for querying a Pkey sid to checkpolicy.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>

---
v1:
Stephen Smalley:
- Removed domain and type params from sepol_ibpkey_sid.
- Removed splen param from sepol_ibpkey_sid, it never varied.
- Removed extra XPERMS_IOCTL version from policydb_compat_info.
- Confirm that low order bytes of IPv6 addr for subnet prefix is 0's.

James Carter:
- Added ibpkey handling to kernel_to_cil.c and kernel_to_conf.c

v2:
Stephen Smalley:
- Store subnet prefix as 8 bytes. This mooted a couple other comments
  about checking and forcing 0's in the lower 8 bytes.
- Bounds check PKeys values in ocontext_read_selinux.

James Carter:
- Add sorting of pkey ocontexts in kernel_to_common.c
---
 checkpolicy/checkpolicy.c                  | 27 +++++++++++++
 libsepol/include/sepol/policydb/services.h |  8 ++++
 libsepol/src/expand.c                      |  7 ++++
 libsepol/src/kernel_to_cil.c               | 62 +++++++++++++++++++++++++++++
 libsepol/src/kernel_to_common.c            | 19 +++++++++
 libsepol/src/kernel_to_conf.c              | 63 ++++++++++++++++++++++++++++++
 libsepol/src/libsepol.map.in               |  1 +
 libsepol/src/module_to_cil.c               | 41 +++++++++++++++++++
 libsepol/src/policydb.c                    | 37 ++++++++++++++++++
 libsepol/src/services.c                    | 37 ++++++++++++++++++
 libsepol/src/write.c                       | 16 ++++++++
 11 files changed, 318 insertions(+)

diff --git a/checkpolicy/checkpolicy.c b/checkpolicy/checkpolicy.c
index 534fc22e..8aeecc1b 100644
--- a/checkpolicy/checkpolicy.c
+++ b/checkpolicy/checkpolicy.c
@@ -22,6 +22,7 @@
  *
  *	Policy Module support.
  *
+ * Copyright (C) 2017 Mellanox Technologies Inc.
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2005 Tresys Technology, LLC
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@@ -699,6 +700,7 @@ int main(int argc, char **argv)
 	printf("h)  change a boolean value\n");
 	printf("i)  display constraint expressions\n");
 	printf("j)  display validatetrans expressions\n");
+	printf("k)  Call ibpkey_sid\n");
 #ifdef EQUIVTYPES
 	printf("z)  Show equivalent types\n");
 #endif
@@ -1220,6 +1222,31 @@ int main(int argc, char **argv)
 				    "\nNo validatetrans expressions found.\n");
 			}
 			break;
+		case 'k':
+			{
+				char *p;
+				struct in6_addr addr6;
+				uint64_t subnet_prefix;
+				unsigned int pkey;
+
+				printf("subnet prefix?  ");
+				FGETS(ans, sizeof(ans), stdin);
+				ans[strlen(ans) - 1] = 0;
+				p = (char *)&addr6;
+
+				if (inet_pton(AF_INET6, ans, p) < 1) {
+					printf("error parsing subnet prefix\n");
+					break;
+				}
+
+				memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
+				printf("pkey? ");
+				FGETS(ans, sizeof(ans), stdin);
+				pkey = atoi(ans);
+				sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
+				printf("sid %d\n", ssid);
+			}
+			break;
 #ifdef EQUIVTYPES
 		case 'z':
 			identify_equiv_types();
diff --git a/libsepol/include/sepol/policydb/services.h b/libsepol/include/sepol/policydb/services.h
index 9162149a..3f3b95d1 100644
--- a/libsepol/include/sepol/policydb/services.h
+++ b/libsepol/include/sepol/policydb/services.h
@@ -188,6 +188,14 @@ extern int sepol_port_sid(uint16_t domain,
 			  uint16_t port, sepol_security_id_t * out_sid);
 
 /*
+ * Return the SID of the ibpkey specified by
+ * `subnet prefix', and `pkey'.
+ */
+extern int sepol_ibpkey_sid(uint64_t subnet_prefix_p,
+			    uint16_t pkey,
+			    sepol_security_id_t *out_sid);
+
+/*
  * Return the SIDs to use for a network interface
  * with the name `name'.  The `if_sid' SID is returned for 
  * the interface and the `msg_sid' SID is returned as
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index 54bf781d..e4cfc41e 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 2004-2005 Tresys Technology, LLC
  * Copyright (C) 2007 Red Hat, Inc.
+ * Copyright (C) 2017 Mellanox Technologies, Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -2217,6 +2218,12 @@ static int ocontext_copy_selinux(expand_state_t *state)
 					return -1;
 				}
 				break;
+			case OCON_IBPKEY:
+				n->u.ibpkey.subnet_prefix = c->u.ibpkey.subnet_prefix;
+
+				n->u.ibpkey.low_pkey = c->u.ibpkey.low_pkey;
+				n->u.ibpkey.high_pkey = c->u.ibpkey.high_pkey;
+			break;
 			case OCON_PORT:
 				n->u.port.protocol = c->u.port.protocol;
 				n->u.port.low_port = c->u.port.low_port;
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index 3a1c0be7..d1006186 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -2784,6 +2784,63 @@ exit:
 	return rc;
 }
 
+static int write_selinux_ibpkey_rules_to_cil(FILE *out, struct policydb *pdb)
+{
+	struct ocontext *ibpkeycon;
+	char subnet_prefix_str[INET6_ADDRSTRLEN];
+	struct in6_addr subnet_prefix = {0};
+	uint16_t low;
+	uint16_t high;
+	char low_high_str[44]; /* 2^64 <= 20 digits so "(low high)" <= 44 chars */
+	char *ctx;
+	int rc = 0;
+
+	for (ibpkeycon = pdb->ocontexts[OCON_IBPKEY]; ibpkeycon != NULL;
+	     ibpkeycon = ibpkeycon->next) {
+		memcpy(&subnet_prefix.s6_addr, &ibpkeycon->u.ibpkey.subnet_prefix,
+		       sizeof(ibpkeycon->u.ibpkey.subnet_prefix));
+
+		if (inet_ntop(AF_INET6, &subnet_prefix.s6_addr,
+			      subnet_prefix_str, INET6_ADDRSTRLEN) == NULL) {
+			sepol_log_err("ibpkeycon subnet_prefix is invalid: %s",
+				      strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		low = ibpkeycon->u.ibpkey.low_pkey;
+		high = ibpkeycon->u.ibpkey.high_pkey;
+		if (low == high) {
+			rc = snprintf(low_high_str, 44, "%u", low);
+		} else {
+			rc = snprintf(low_high_str, 44, "(%u %u)", low, high);
+		}
+		if (rc < 0 || rc >= 44) {
+			rc = -1;
+			goto exit;
+		}
+
+		ctx = context_to_str(pdb, &ibpkeycon->context[0]);
+		if (!ctx) {
+			rc = -1;
+			goto exit;
+		}
+
+		sepol_printf(out, "(ibpkeycon %s %s %s)\n", subnet_prefix_str, low_high_str, ctx);
+
+		free(ctx);
+	}
+
+	rc = 0;
+
+exit:
+	if (rc != 0) {
+		sepol_log_err("Error writing ibpkeycon rules to CIL\n");
+	}
+
+	return rc;
+}
+
 static int write_xen_isid_rules_to_cil(FILE *out, struct policydb *pdb)
 {
 	return write_sid_context_rules_to_cil(out, pdb, xen_sid_to_str);
@@ -3180,6 +3237,11 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb)
 		if (rc != 0) {
 			goto exit;
 		}
+
+		rc = write_selinux_ibpkey_rules_to_cil(out, pdb);
+		if (rc != 0) {
+			goto exit;
+		}
 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
 		rc = write_xen_isid_rules_to_cil(out, pdb);
 		if (rc != 0) {
diff --git a/libsepol/src/kernel_to_common.c b/libsepol/src/kernel_to_common.c
index 45adc5d5..294f0b4e 100644
--- a/libsepol/src/kernel_to_common.c
+++ b/libsepol/src/kernel_to_common.c
@@ -518,6 +518,20 @@ static int node6_data_cmp(const void *a, const void *b)
 	return memcmp(&(*aa)->u.node6.addr, &(*bb)->u.node6.addr, sizeof((*aa)->u.node6.addr));
 }
 
+static int ibpkey_data_cmp(const void *a, const void *b)
+{
+	int rc;
+	struct ocontext *const *aa = a;
+	struct ocontext *const *bb = b;
+
+	rc = (*aa)->u.ibpkey.subnet_prefix - (*bb)->u.ibpkey.subnet_prefix;
+	if (rc)
+		return rc;
+
+	return compare_ranges((*aa)->u.ibpkey.low_pkey, (*aa)->u.ibpkey.high_pkey,
+			      (*bb)->u.ibpkey.low_pkey, (*bb)->u.ibpkey.high_pkey);
+}
+
 static int pirq_data_cmp(const void *a, const void *b)
 {
 	struct ocontext *const *aa = a;
@@ -641,6 +655,11 @@ int sort_ocontexts(struct policydb *pdb)
 		if (rc != 0) {
 			goto exit;
 		}
+
+		rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBPKEY], ibpkey_data_cmp);
+		if (rc != 0) {
+			goto exit;
+		}
 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
 		rc = sort_ocontext_data(&pdb->ocontexts[1], pirq_data_cmp);
 		if (rc != 0) {
diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index 22a09095..23307ce6 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -2645,6 +2645,64 @@ exit:
 	return rc;
 }
 
+static int write_selinux_ibpkey_rules_to_conf(FILE *out, struct policydb *pdb)
+{
+	struct ocontext *ibpkeycon;
+	char subnet_prefix_str[INET6_ADDRSTRLEN];
+	struct in6_addr subnet_prefix = {0};
+	uint16_t low;
+	uint16_t high;
+	char low_high_str[44]; /* 2^64 <= 20 digits so "low-high" <= 44 chars */
+	char *ctx;
+	int rc = 0;
+
+	for (ibpkeycon = pdb->ocontexts[OCON_IBPKEY]; ibpkeycon != NULL;
+	     ibpkeycon = ibpkeycon->next) {
+		memcpy(&subnet_prefix.s6_addr, &ibpkeycon->u.ibpkey.subnet_prefix,
+		       sizeof(ibpkeycon->u.ibpkey.subnet_prefix));
+
+		if (inet_ntop(AF_INET6, &subnet_prefix.s6_addr,
+			      subnet_prefix_str, INET6_ADDRSTRLEN) == NULL) {
+			sepol_log_err("ibpkeycon address is invalid: %s",
+				      strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		low = ibpkeycon->u.ibpkey.low_pkey;
+		high = ibpkeycon->u.ibpkey.high_pkey;
+		if (low == high) {
+			rc = snprintf(low_high_str, 44, "%u", low);
+		} else {
+			rc = snprintf(low_high_str, 44, "%u-%u", low, high);
+		}
+		if (rc < 0 || rc >= 44) {
+			rc = -1;
+			goto exit;
+		}
+
+		ctx = context_to_str(pdb, &ibpkeycon->context[0]);
+		if (!ctx) {
+			rc = -1;
+			goto exit;
+		}
+
+		sepol_printf(out, "ibpkeycon %s %s %s\n", subnet_prefix_str,
+			     low_high_str, ctx);
+
+		free(ctx);
+	}
+
+	rc = 0;
+
+exit:
+	if (rc != 0) {
+		sepol_log_err("Error writing ibpkeycon rules to policy.conf\n");
+	}
+
+	return rc;
+}
+
 static int write_xen_isid_rules_to_conf(FILE *out, struct policydb *pdb)
 {
 	return write_sid_context_rules_to_conf(out, pdb, xen_sid_to_str);
@@ -3045,6 +3103,11 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
 		if (rc != 0) {
 			goto exit;
 		}
+
+		rc = write_selinux_ibpkey_rules_to_conf(out, pdb);
+		if (rc != 0) {
+			goto exit;
+		}
 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
 		rc = write_xen_isid_rules_to_conf(out, pdb);
 		if (rc != 0) {
diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in
index 40426408..36225d1c 100644
--- a/libsepol/src/libsepol.map.in
+++ b/libsepol/src/libsepol.map.in
@@ -6,6 +6,7 @@ LIBSEPOL_1.0 {
 	sepol_context_*; sepol_mls_*; sepol_check_context;
 	sepol_iface_*; 
 	sepol_port_*;
+	sepol_ibpkey_*;
 	sepol_node_*;
 	sepol_user_*; sepol_genusers; sepol_set_delusers;
 	sepol_msg_*; sepol_debug;
diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
index 7d8eb204..10d0700c 100644
--- a/libsepol/src/module_to_cil.c
+++ b/libsepol/src/module_to_cil.c
@@ -3,6 +3,7 @@
  * Functions to convert policy module to CIL
  *
  * Copyright (C) 2015 Tresys Technology, LLC
+ * Copyright (C) 2017 Mellanox Technologies Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -2656,6 +2657,45 @@ exit:
 	return rc;
 }
 
+static int ocontext_selinux_ibpkey_to_cil(struct policydb *pdb,
+					struct ocontext *ibpkeycons)
+{
+	int rc = -1;
+	struct ocontext *ibpkeycon;
+	char subnet_prefix_str[INET6_ADDRSTRLEN];
+	struct in6_addr subnet_prefix = {0};
+	uint16_t high;
+	uint16_t low;
+
+	for (ibpkeycon = ibpkeycons; ibpkeycon; ibpkeycon = ibpkeycon->next) {
+		low = ibpkeycon->u.ibpkey.low_pkey;
+		high = ibpkeycon->u.ibpkey.high_pkey;
+		memcpy(&subnet_prefix.s6_addr, &ibpkeycon->u.ibpkey.subnet_prefix,
+		       sizeof(ibpkeycon->u.ibpkey.subnet_prefix));
+
+		if (inet_ntop(AF_INET6, &subnet_prefix.s6_addr,
+			      subnet_prefix_str, INET6_ADDRSTRLEN) == NULL) {
+			log_err("ibpkeycon subnet_prefix is invalid: %s",
+				strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		if (low == high)
+			cil_printf("(ibpkeycon %s %i ", subnet_prefix_str, low);
+		else
+			cil_printf("(ibpkeycon %s (%i %i) ", subnet_prefix_str, low,
+				   high);
+
+		context_to_cil(pdb, &ibpkeycon->context[0]);
+
+		cil_printf(")\n");
+	}
+	return 0;
+exit:
+	return rc;
+}
+
 static int ocontext_selinux_netif_to_cil(struct policydb *pdb, struct ocontext *netifs)
 {
 	struct ocontext *netif;
@@ -2889,6 +2929,7 @@ static int ocontexts_to_cil(struct policydb *pdb)
 		ocontext_selinux_node_to_cil,
 		ocontext_selinux_fsuse_to_cil,
 		ocontext_selinux_node6_to_cil,
+		ocontext_selinux_ibpkey_to_cil,
 	};
 	static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
 		ocontext_xen_isid_to_cil,
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index b1530955..09d14140 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -18,6 +18,7 @@
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2005 Tresys Technology, LLC
  * Copyright (C) 2003 - 2007 Red Hat, Inc.
+ * Copyright (C) 2017 Mellanox Technologies Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -186,6 +187,13 @@ static struct policydb_compat_info policydb_compat[] = {
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
 	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_INFINIBAND,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_IBPKEY + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
 	 .type = POLICY_BASE,
 	 .version = MOD_POLICYDB_VERSION_BASE,
 	 .sym_num = SYM_NUM,
@@ -291,6 +299,13 @@ static struct policydb_compat_info policydb_compat[] = {
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
 	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_INFINIBAND,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_IBPKEY + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
+	{
 	 .type = POLICY_MOD,
 	 .version = MOD_POLICYDB_VERSION_BASE,
 	 .sym_num = SYM_NUM,
@@ -395,6 +410,13 @@ static struct policydb_compat_info policydb_compat[] = {
 	 .ocon_num = 0,
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_INFINIBAND,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
 };
 
 #if 0
@@ -2798,6 +2820,21 @@ static int ocontext_read_selinux(struct policydb_compat_info *info,
 				    (&c->context[1], p, fp))
 					return -1;
 				break;
+			case OCON_IBPKEY:
+				rc = next_entry(buf, fp, sizeof(uint32_t) * 4);
+				if (rc < 0 || buf[2] > 0xffff || buf[3] > 0xffff)
+					return -1;
+
+				memcpy(&c->u.ibpkey.subnet_prefix, buf,
+				       sizeof(c->u.ibpkey.subnet_prefix));
+
+				c->u.ibpkey.low_pkey = le32_to_cpu(buf[2]);
+				c->u.ibpkey.high_pkey = le32_to_cpu(buf[3]);
+
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
 			case OCON_PORT:
 				rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
 				if (rc < 0)
diff --git a/libsepol/src/services.c b/libsepol/src/services.c
index 03fb1203..27e802c6 100644
--- a/libsepol/src/services.c
+++ b/libsepol/src/services.c
@@ -21,6 +21,7 @@
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  * Copyright (C) 2003 - 2004 Red Hat, Inc.
+ * Copyright (C) 2017 Mellanox Technologies Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -1911,6 +1912,42 @@ int hidden sepol_fs_sid(char *name,
 }
 
 /*
+ * Return the SID of the ibpkey specified by
+ * `subnet prefix', and `pkey number'.
+ */
+int hidden sepol_ibpkey_sid(uint64_t subnet_prefix,
+			    uint16_t pkey, sepol_security_id_t *out_sid)
+{
+	ocontext_t *c;
+	int rc = 0;
+
+	c = policydb->ocontexts[OCON_IBPKEY];
+	while (c) {
+		if (c->u.ibpkey.low_pkey <= pkey &&
+		    c->u.ibpkey.high_pkey >= pkey &&
+		    subnet_prefix == c->u.ibpkey.subnet_prefix)
+			break;
+		c = c->next;
+	}
+
+	if (c) {
+		if (!c->sid[0]) {
+			rc = sepol_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:
+	return rc;
+}
+
+/*
  * Return the SID of the port specified by
  * `domain', `type', `protocol', and `port'.
  */
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index 1606807d..f63e7489 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -16,6 +16,7 @@
  *
  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003-2005 Tresys Technology, LLC
+ * Copyright (C) 2017 Mellanox Technologies Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -1411,6 +1412,21 @@ static int ocontext_write_selinux(struct policydb_compat_info *info,
 				if (context_write(p, &c->context[1], fp))
 					return POLICYDB_ERROR;
 				break;
+			case OCON_IBPKEY:
+				 /* The subnet prefix is in network order */
+				memcpy(buf, &c->u.ibpkey.subnet_prefix,
+				       sizeof(c->u.ibpkey.subnet_prefix));
+
+				buf[2] = cpu_to_le32(c->u.ibpkey.low_pkey);
+				buf[3] = cpu_to_le32(c->u.ibpkey.high_pkey);
+
+				items = put_entry(buf, sizeof(uint32_t), 4, fp);
+				if (items != 4)
+					return POLICYDB_ERROR;
+
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
 			case OCON_PORT:
 				buf[0] = c->u.port.protocol;
 				buf[1] = c->u.port.low_port;
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/9] libsepol: Add Infiniband Pkey handling to CIL
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 1/9] checkpolicy: Add support for ibpkeycon labels Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 2/9] libsepol: Add ibpkey ocontext handling Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 4/9] checkpolicy: Add support for ibendportcon labels Dan Jurgens
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Add Infiniband pkey parsing, symbol table management, and policy
generation to CIL.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>
---
 libsepol/cil/src/cil.c             | 19 +++++++++
 libsepol/cil/src/cil_binary.c      | 39 +++++++++++++++++
 libsepol/cil/src/cil_binary.h      | 12 ++++++
 libsepol/cil/src/cil_build_ast.c   | 86 ++++++++++++++++++++++++++++++++++++++
 libsepol/cil/src/cil_build_ast.h   |  2 +
 libsepol/cil/src/cil_copy_ast.c    | 26 ++++++++++++
 libsepol/cil/src/cil_copy_ast.h    |  1 +
 libsepol/cil/src/cil_flavor.h      |  1 +
 libsepol/cil/src/cil_internal.h    | 11 +++++
 libsepol/cil/src/cil_policy.c      | 16 +++++++
 libsepol/cil/src/cil_post.c        | 45 ++++++++++++++++++++
 libsepol/cil/src/cil_post.h        |  1 +
 libsepol/cil/src/cil_reset_ast.c   |  9 ++++
 libsepol/cil/src/cil_resolve_ast.c | 27 ++++++++++++
 libsepol/cil/src/cil_resolve_ast.h |  1 +
 libsepol/cil/src/cil_tree.c        | 16 ++++++-
 libsepol/cil/src/cil_verify.c      | 23 ++++++++++
 17 files changed, 334 insertions(+), 1 deletion(-)

diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
index 9b9ccc36..3df670a7 100644
--- a/libsepol/cil/src/cil.c
+++ b/libsepol/cil/src/cil.c
@@ -188,6 +188,7 @@ static void cil_init_keys(void)
 	CIL_KEY_MLSVALIDATETRANS = cil_strpool_add("mlsvalidatetrans");
 	CIL_KEY_CONTEXT = cil_strpool_add("context");
 	CIL_KEY_FILECON = cil_strpool_add("filecon");
+	CIL_KEY_IBPKEYCON = cil_strpool_add("ibpkeycon");
 	CIL_KEY_PORTCON = cil_strpool_add("portcon");
 	CIL_KEY_NODECON = cil_strpool_add("nodecon");
 	CIL_KEY_GENFSCON = cil_strpool_add("genfscon");
@@ -257,6 +258,7 @@ void cil_db_init(struct cil_db **db)
 	cil_sort_init(&(*db)->genfscon);
 	cil_sort_init(&(*db)->filecon);
 	cil_sort_init(&(*db)->nodecon);
+	cil_sort_init(&(*db)->ibpkeycon);
 	cil_sort_init(&(*db)->portcon);
 	cil_sort_init(&(*db)->pirqcon);
 	cil_sort_init(&(*db)->iomemcon);
@@ -308,6 +310,7 @@ void cil_db_destroy(struct cil_db **db)
 	cil_sort_destroy(&(*db)->genfscon);
 	cil_sort_destroy(&(*db)->filecon);
 	cil_sort_destroy(&(*db)->nodecon);
+	cil_sort_destroy(&(*db)->ibpkeycon);
 	cil_sort_destroy(&(*db)->portcon);
 	cil_sort_destroy(&(*db)->pirqcon);
 	cil_sort_destroy(&(*db)->iomemcon);
@@ -728,6 +731,9 @@ void cil_destroy_data(void **data, enum cil_flavor flavor)
 	case CIL_FILECON:
 		cil_destroy_filecon(*data);
 		break;
+	case CIL_IBPKEYCON:
+		cil_destroy_ibpkeycon(*data);
+		break;
 	case CIL_PORTCON:
 		cil_destroy_portcon(*data);
 		break;
@@ -1097,6 +1103,8 @@ const char * cil_node_to_string(struct cil_tree_node *node)
 		return CIL_KEY_FSUSE;
 	case CIL_FILECON:
 		return CIL_KEY_FILECON;
+	case CIL_IBPKEYCON:
+		return CIL_KEY_IBPKEYCON;
 	case CIL_PORTCON:
 		return CIL_KEY_PORTCON;
 	case CIL_NODECON:
@@ -2255,6 +2263,17 @@ void cil_filecon_init(struct cil_filecon **filecon)
 	(*filecon)->context = NULL;
 }
 
+void cil_ibpkeycon_init(struct cil_ibpkeycon **ibpkeycon)
+{
+	*ibpkeycon = cil_malloc(sizeof(**ibpkeycon));
+
+	(*ibpkeycon)->subnet_prefix_str = NULL;
+	(*ibpkeycon)->pkey_low = 0;
+	(*ibpkeycon)->pkey_high = 0;
+	(*ibpkeycon)->context_str = NULL;
+	(*ibpkeycon)->context = NULL;
+}
+
 void cil_portcon_init(struct cil_portcon **portcon)
 {
 	*portcon = cil_malloc(sizeof(**portcon));
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index e1481a43..1ddbf21f 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -3218,6 +3218,40 @@ exit:
 	return rc;
 }
 
+int cil_ibpkeycon_to_policydb(policydb_t *pdb, struct cil_sort *ibpkeycons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i = 0;
+	ocontext_t *tail = NULL;
+	struct in6_addr subnet_prefix;
+
+	for (i = 0; i < ibpkeycons->count; i++) {
+		struct cil_ibpkeycon *cil_ibpkeycon = ibpkeycons->array[i];
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_IBPKEY], &tail);
+
+		rc = inet_pton(AF_INET6, cil_ibpkeycon->subnet_prefix_str, &subnet_prefix);
+		if (rc != 1) {
+			cil_log(CIL_ERR, "ibpkeycon subnet prefix not in valid IPV6 format\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+
+		memcpy(&new_ocon->u.ibpkey.subnet_prefix, &subnet_prefix.s6_addr[0],
+		       sizeof(new_ocon->u.ibpkey.subnet_prefix));
+		new_ocon->u.ibpkey.low_pkey = cil_ibpkeycon->pkey_low;
+		new_ocon->u.ibpkey.high_pkey = cil_ibpkeycon->pkey_high;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_ibpkeycon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
 int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons)
 {
 	int rc = SEPOL_ERR;
@@ -3848,6 +3882,11 @@ int __cil_contexts_to_policydb(policydb_t *pdb, const struct cil_db *db)
 		goto exit;
 	}
 
+	rc = cil_ibpkeycon_to_policydb(pdb, db->ibpkeycon);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
 	if (db->target_platform == SEPOL_TARGET_XEN) {
 		rc = cil_pirqcon_to_policydb(pdb, db->pirqcon);
 		if (rc != SEPOL_OK) {
diff --git a/libsepol/cil/src/cil_binary.h b/libsepol/cil/src/cil_binary.h
index c59b1e3c..a03d250d 100644
--- a/libsepol/cil/src/cil_binary.h
+++ b/libsepol/cil/src/cil_binary.h
@@ -330,6 +330,18 @@ int cil_sepol_level_define(policydb_t *pdb, struct cil_sens *cil_sens);
 int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_rangetransition *rangetrans, hashtab_t range_trans_table);
 
 /**
+ * Insert cil ibpkeycon structure into sepol policydb.
+ * The function is given a structure containing the sorted ibpkeycons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the ibpkeycon into.
+ * @param[in] node The cil_sort structure that contains the sorted ibpkeycons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_ibpkeycon_to_policydb(policydb_t *pdb, struct cil_sort *ibpkeycons);
+
+/**
  * Insert cil portcon structure into sepol policydb.
  * The function is given a structure containing the sorted portcons and
  * loops over this structure inserting them into the policy database.
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
index 36cc6735..11215744 100644
--- a/libsepol/cil/src/cil_build_ast.c
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -4256,6 +4256,89 @@ void cil_destroy_filecon(struct cil_filecon *filecon)
 	free(filecon);
 }
 
+int cil_gen_ibpkeycon(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax) / sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_ibpkeycon *ibpkeycon = NULL;
+
+	if (!db || !parse_current || !ast_node)
+		goto exit;
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK)
+		goto exit;
+
+	cil_ibpkeycon_init(&ibpkeycon);
+
+	ibpkeycon->subnet_prefix_str = parse_current->next->data;
+
+	if (parse_current->next->next->cl_head) {
+		if (parse_current->next->next->cl_head->next &&
+		    !parse_current->next->next->cl_head->next->next) {
+			rc = cil_fill_integer(parse_current->next->next->cl_head, &ibpkeycon->pkey_low, 0);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper ibpkey specified\n");
+				goto exit;
+			}
+			rc = cil_fill_integer(parse_current->next->next->cl_head->next, &ibpkeycon->pkey_high, 0);
+			if (rc != SEPOL_OK) {
+				cil_log(CIL_ERR, "Improper ibpkey specified\n");
+				goto exit;
+			}
+		} else {
+			cil_log(CIL_ERR, "Improper ibpkey range specified\n");
+			rc = SEPOL_ERR;
+			goto exit;
+		}
+	} else {
+		rc = cil_fill_integer(parse_current->next->next, &ibpkeycon->pkey_low, 0);
+		if (rc != SEPOL_OK) {
+			cil_log(CIL_ERR, "Improper ibpkey specified\n");
+			goto exit;
+		}
+		ibpkeycon->pkey_high = ibpkeycon->pkey_low;
+	}
+
+	if (!parse_current->next->next->next->cl_head) {
+		ibpkeycon->context_str = parse_current->next->next->next->data;
+	} else {
+		cil_context_init(&ibpkeycon->context);
+
+		rc = cil_fill_context(parse_current->next->next->next->cl_head, ibpkeycon->context);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	ast_node->data = ibpkeycon;
+	ast_node->flavor = CIL_IBPKEYCON;
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad ibpkeycon declaration");
+	cil_destroy_ibpkeycon(ibpkeycon);
+
+	return rc;
+}
+
+void cil_destroy_ibpkeycon(struct cil_ibpkeycon *ibpkeycon)
+{
+	if (!ibpkeycon)
+		return;
+
+	if (!ibpkeycon->context_str && ibpkeycon->context)
+		cil_destroy_context(ibpkeycon->context);
+
+	free(ibpkeycon);
+}
+
 int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
 {
 	enum cil_syntax syntax[] = {
@@ -6215,6 +6298,9 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
 	} else if (parse_current->data == CIL_KEY_FILECON) {
 		rc = cil_gen_filecon(db, parse_current, ast_node);
 		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_IBPKEYCON) {
+		rc = cil_gen_ibpkeycon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
 	} else if (parse_current->data == CIL_KEY_PORTCON) {
 		rc = cil_gen_portcon(db, parse_current, ast_node);
 		*finished = CIL_TREE_SKIP_NEXT;
diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h
index 33bae997..c2d7b31e 100644
--- a/libsepol/cil/src/cil_build_ast.h
+++ b/libsepol/cil/src/cil_build_ast.h
@@ -175,6 +175,8 @@ int cil_gen_context(struct cil_db *db, struct cil_tree_node *parse_current, stru
 void cil_destroy_context(struct cil_context *context);
 int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
 void cil_destroy_filecon(struct cil_filecon *filecon);
+int cil_gen_ibpkeycon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_ibpkeycon(struct cil_ibpkeycon *ibpkeycon);
 int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
 void cil_destroy_portcon(struct cil_portcon *portcon);
 int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
index d6685050..7307b08b 100644
--- a/libsepol/cil/src/cil_copy_ast.c
+++ b/libsepol/cil/src/cil_copy_ast.c
@@ -1204,6 +1204,29 @@ int cil_copy_nodecon(struct cil_db *db, void *data, void **copy, __attribute__((
 	return SEPOL_OK;
 }
 
+int cil_copy_ibpkeycon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_ibpkeycon *orig = data;
+	struct cil_ibpkeycon *new = NULL;
+
+	cil_ibpkeycon_init(&new);
+
+	new->subnet_prefix_str = orig->subnet_prefix_str;
+	new->pkey_low = orig->pkey_low;
+	new->pkey_high = orig->pkey_high;
+
+	if (orig->context_str) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
 int cil_copy_portcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
 {
 	struct cil_portcon *orig = data;
@@ -1916,6 +1939,9 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u
 	case CIL_NODECON:
 		copy_func = &cil_copy_nodecon;
 		break;
+	case CIL_IBPKEYCON:
+		copy_func = &cil_copy_ibpkeycon;
+		break;
 	case CIL_PORTCON:
 		copy_func = &cil_copy_portcon;
 		break;
diff --git a/libsepol/cil/src/cil_copy_ast.h b/libsepol/cil/src/cil_copy_ast.h
index 78c34b87..a50c3708 100644
--- a/libsepol/cil/src/cil_copy_ast.h
+++ b/libsepol/cil/src/cil_copy_ast.h
@@ -99,6 +99,7 @@ int cil_copy_netifcon(struct cil_db *db, void *data, void **copy, symtab_t *symt
 int cil_copy_genfscon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
 int cil_copy_filecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
 int cil_copy_nodecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
+int cil_copy_ibpkeycon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
 int cil_copy_portcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
 int cil_copy_pirqcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
 int cil_copy_iomemcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
diff --git a/libsepol/cil/src/cil_flavor.h b/libsepol/cil/src/cil_flavor.h
index c01f967a..4505b8bb 100644
--- a/libsepol/cil/src/cil_flavor.h
+++ b/libsepol/cil/src/cil_flavor.h
@@ -113,6 +113,7 @@ enum cil_flavor {
 	CIL_HANDLEUNKNOWN,
 	CIL_MLS,
 	CIL_SRC_INFO,
+	CIL_IBPKEYCON,
 
 /*
  *          boolean  constraint  set  catset
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
index aee3f00c..2add97bb 100644
--- a/libsepol/cil/src/cil_internal.h
+++ b/libsepol/cil/src/cil_internal.h
@@ -203,6 +203,7 @@ char *CIL_KEY_VALIDATETRANS;
 char *CIL_KEY_MLSVALIDATETRANS;
 char *CIL_KEY_CONTEXT;
 char *CIL_KEY_FILECON;
+char *CIL_KEY_IBPKEYCON;
 char *CIL_KEY_PORTCON;
 char *CIL_KEY_NODECON;
 char *CIL_KEY_GENFSCON;
@@ -286,6 +287,7 @@ struct cil_db {
 	struct cil_sort *genfscon;
 	struct cil_sort *filecon;
 	struct cil_sort *nodecon;
+	struct cil_sort *ibpkeycon;
 	struct cil_sort *portcon;
 	struct cil_sort *pirqcon;
 	struct cil_sort *iomemcon;
@@ -737,6 +739,14 @@ enum cil_protocol {
 	CIL_PROTOCOL_DCCP
 };
 
+struct cil_ibpkeycon {
+	char *subnet_prefix_str;
+	uint32_t pkey_low;
+	uint32_t pkey_high;
+	char *context_str;
+	struct cil_context *context;
+};
+
 struct cil_portcon {
 	enum cil_protocol proto;
 	uint32_t port_low;
@@ -1007,6 +1017,7 @@ void cil_catset_init(struct cil_catset **catset);
 void cil_cats_init(struct cil_cats **cats);
 void cil_senscat_init(struct cil_senscat **senscat);
 void cil_filecon_init(struct cil_filecon **filecon);
+void cil_ibpkeycon_init(struct cil_ibpkeycon **ibpkeycon);
 void cil_portcon_init(struct cil_portcon **portcon);
 void cil_nodecon_init(struct cil_nodecon **nodecon);
 void cil_genfscon_init(struct cil_genfscon **genfscon);
diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
index 77179e63..35a0a29e 100644
--- a/libsepol/cil/src/cil_policy.c
+++ b/libsepol/cil/src/cil_policy.c
@@ -1714,6 +1714,21 @@ static void cil_genfscons_to_policy(FILE *out, struct cil_sort *genfscons, int m
 	}
 }
 
+static void cil_ibpkeycons_to_policy(FILE *out, struct cil_sort *ibpkeycons, int mls)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < ibpkeycons->count; i++) {
+		struct cil_ibpkeycon *ibpkeycon = (struct cil_ibpkeycon *)ibpkeycons->array[i];
+
+		fprintf(out, "ibpkeycon %s ", ibpkeycon->subnet_prefix_str);
+		fprintf(out, "%d ", ibpkeycon->pkey_low);
+		fprintf(out, "%d ", ibpkeycon->pkey_high);
+		cil_context_to_policy(out, ibpkeycon->context, mls);
+		fprintf(out, "\n");
+	}
+}
+
 static void cil_portcons_to_policy(FILE *out, struct cil_sort *portcons, int mls)
 {
 	unsigned i;
@@ -1942,6 +1957,7 @@ void cil_gen_policy(FILE *out, struct cil_db *db)
 	cil_genfscons_to_policy(out, db->genfscon, db->mls);
 	cil_portcons_to_policy(out, db->portcon, db->mls);
 	cil_netifcons_to_policy(out, db->netifcon, db->mls);
+	cil_ibpkeycons_to_policy(out, db->ibpkeycon, db->mls);
 	cil_nodecons_to_policy(out, db->nodecon, db->mls);
 	cil_pirqcons_to_policy(out, db->pirqcon, db->mls);
 	cil_iomemcons_to_policy(out, db->iomemcon, db->mls);
diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
index 1941fab3..893860d5 100644
--- a/libsepol/cil/src/cil_post.c
+++ b/libsepol/cil/src/cil_post.c
@@ -154,6 +154,28 @@ int cil_post_filecon_compare(const void *a, const void *b)
 	return rc;
 }
 
+int cil_post_ibpkeycon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+	struct cil_ibpkeycon *aibpkeycon = *(struct cil_ibpkeycon **)a;
+	struct cil_ibpkeycon *bibpkeycon = *(struct cil_ibpkeycon **)b;
+
+	rc = strcmp(aibpkeycon->subnet_prefix_str, bibpkeycon->subnet_prefix_str);
+	if (rc)
+		return rc;
+
+	rc = (aibpkeycon->pkey_high - aibpkeycon->pkey_low)
+		- (bibpkeycon->pkey_high - bibpkeycon->pkey_low);
+	if (rc == 0) {
+		if (aibpkeycon->pkey_low < bibpkeycon->pkey_low)
+			rc = -1;
+		else if (bibpkeycon->pkey_low < aibpkeycon->pkey_low)
+			rc = 1;
+	}
+
+	return rc;
+}
+
 int cil_post_portcon_compare(const void *a, const void *b)
 {
 	int rc = SEPOL_ERR;
@@ -401,6 +423,9 @@ static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *fini
 	case CIL_NODECON:
 		db->nodecon->count++;
 		break;
+	case CIL_IBPKEYCON:
+		db->ibpkeycon->count++;
+		break;
 	case CIL_PORTCON:
 		db->portcon->count++;
 		break;
@@ -535,6 +560,17 @@ static int __cil_post_db_array_helper(struct cil_tree_node *node, uint32_t *fini
 		sort->index++;
 		break;
 	}
+	case CIL_IBPKEYCON: {
+		struct cil_sort *sort = db->ibpkeycon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+
+		if (!sort->array)
+			sort->array = cil_malloc(sizeof(*sort->array) * count);
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
 	case CIL_PORTCON: {
 		struct cil_sort *sort = db->portcon;
 		uint32_t count = sort->count;
@@ -1618,6 +1654,14 @@ static int __cil_post_db_cat_helper(struct cil_tree_node *node, uint32_t *finish
 		}
 		break;
 	}
+	case CIL_IBPKEYCON: {
+		struct cil_ibpkeycon *ibpkeycon = node->data;
+
+		rc = __evaluate_levelrange_expression(ibpkeycon->context->range, db);
+		if (rc != SEPOL_OK)
+			goto exit;
+		break;
+	}
 	case CIL_PORTCON: {
 		struct cil_portcon *portcon = node->data;
 		rc = __evaluate_levelrange_expression(portcon->context->range, db);
@@ -1977,6 +2021,7 @@ static int cil_post_db(struct cil_db *db)
 
 	qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
 	qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
+	qsort(db->ibpkeycon->array, db->ibpkeycon->count, sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
 	qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
 	qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
 	qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
diff --git a/libsepol/cil/src/cil_post.h b/libsepol/cil/src/cil_post.h
index 74393ccf..fe7f3a58 100644
--- a/libsepol/cil/src/cil_post.h
+++ b/libsepol/cil/src/cil_post.h
@@ -38,6 +38,7 @@ struct fc_data {
 
 void cil_post_fc_fill_data(struct fc_data *fc, char *path);
 int cil_post_filecon_compare(const void *a, const void *b);
+int cil_post_ibpkeycon_compare(const void *a, const void *b);
 int cil_post_portcon_compare(const void *a, const void *b);
 int cil_post_genfscon_compare(const void *a, const void *b);
 int cil_post_netifcon_compare(const void *a, const void *b);
diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c
index 676e156e..fc23a2c8 100644
--- a/libsepol/cil/src/cil_reset_ast.c
+++ b/libsepol/cil/src/cil_reset_ast.c
@@ -288,6 +288,12 @@ static void cil_reset_filecon(struct cil_filecon *filecon)
 	}
 }
 
+static void cil_reset_ibpkeycon(struct cil_ibpkeycon *ibpkeycon)
+{
+	if (!ibpkeycon->context)
+		cil_reset_context(ibpkeycon->context);
+}
+
 static void cil_reset_portcon(struct cil_portcon *portcon)
 {
 	if (portcon->context_str == NULL) {
@@ -489,6 +495,9 @@ int __cil_reset_node(struct cil_tree_node *node,  __attribute__((unused)) uint32
 	case CIL_FILECON:
 		cil_reset_filecon(node->data);
 		break;
+	case CIL_IBPKEYCON:
+		cil_reset_ibpkeycon(node->data);
+		break;
 	case CIL_PORTCON:
 		cil_reset_portcon(node->data);
 		break;
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
index 8925b271..9e3cb2b5 100644
--- a/libsepol/cil/src/cil_resolve_ast.c
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -1923,6 +1923,30 @@ int cil_resolve_filecon(struct cil_tree_node *current, void *extra_args)
 	return SEPOL_OK;
 }
 
+int cil_resolve_ibpkeycon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_ibpkeycon *ibpkeycon = current->data;
+	struct cil_symtab_datum *context_datum = NULL;
+	int rc = SEPOL_ERR;
+
+	if (ibpkeycon->context_str) {
+		rc = cil_resolve_name(current, ibpkeycon->context_str, CIL_SYM_CONTEXTS, extra_args, &context_datum);
+		if (rc != SEPOL_OK)
+			goto exit;
+
+		ibpkeycon->context = (struct cil_context *)context_datum;
+	} else {
+		rc = cil_resolve_context(current, ibpkeycon->context, extra_args);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
 int cil_resolve_portcon(struct cil_tree_node *current, void *extra_args)
 {
 	struct cil_portcon *portcon = current->data;
@@ -3567,6 +3591,9 @@ int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
 		case CIL_FILECON:
 			rc = cil_resolve_filecon(node, args);
 			break;
+		case CIL_IBPKEYCON:
+			rc = cil_resolve_ibpkeycon(node, args);
+			break;
 		case CIL_PORTCON:
 			rc = cil_resolve_portcon(node, args);
 			break;
diff --git a/libsepol/cil/src/cil_resolve_ast.h b/libsepol/cil/src/cil_resolve_ast.h
index 1175f974..0506a3de 100644
--- a/libsepol/cil/src/cil_resolve_ast.h
+++ b/libsepol/cil/src/cil_resolve_ast.h
@@ -74,6 +74,7 @@ int cil_resolve_constrain(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_validatetrans(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_context(struct cil_tree_node *current, struct cil_context *context, void *extra_args);
 int cil_resolve_filecon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_ibpkeycon(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_portcon(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_genfscon(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_nodecon(struct cil_tree_node *current, void *extra_args);
diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c
index 2cc2744a..89706d0f 100644
--- a/libsepol/cil/src/cil_tree.c
+++ b/libsepol/cil/src/cil_tree.c
@@ -1,6 +1,6 @@
 /*
  * Copyright 2011 Tresys Technology, LLC. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  * 
@@ -1409,6 +1409,20 @@ void cil_tree_print_node(struct cil_tree_node *node)
 			return;
 
 		}
+		case CIL_IBPKEYCON: {
+			struct cil_ibpkeycon *ibpkeycon = node->data;
+
+			cil_log(CIL_INFO, "IBPKEYCON: %s", ibpkeycon->subnet_prefix_str);
+			cil_log(CIL_INFO, " (%d %d) ", ibpkeycon->pkey_low, ibpkeycon->pkey_high);
+
+			if (ibpkeycon->context)
+				cil_tree_print_context(ibpkeycon->context);
+			else if (ibpkeycon->context_str)
+				cil_log(CIL_INFO, " %s", ibpkeycon->context_str);
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
 		case CIL_PORTCON: {
 			struct cil_portcon *portcon = node->data;
 			cil_log(CIL_INFO, "PORTCON:");
diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c
index 47dcfaa2..108da33d 100644
--- a/libsepol/cil/src/cil_verify.c
+++ b/libsepol/cil/src/cil_verify.c
@@ -1080,6 +1080,26 @@ exit:
 	return rc;
 }
 
+int __cil_verify_ibpkeycon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_ibpkeycon *pkey = node->data;
+	struct cil_context *ctx = pkey->context;
+
+	/* Verify only when anonymous */
+	if (!ctx->datum.name) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid ibpkeycon");
+	return rc;
+}
+
 int __cil_verify_portcon(struct cil_db *db, struct cil_tree_node *node)
 {
 	int rc = SEPOL_ERR;
@@ -1452,6 +1472,9 @@ int __cil_verify_helper(struct cil_tree_node *node, uint32_t *finished, void *ex
 		case CIL_NODECON:
 			rc = __cil_verify_nodecon(db, node);
 			break;
+		case CIL_IBPKEYCON:
+			rc = __cil_verify_ibpkeycon(db, node);
+			break;
 		case CIL_PORTCON:
 			rc = __cil_verify_portcon(db, node);
 			break;
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/9] checkpolicy: Add support for ibendportcon labels
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
                   ` (2 preceding siblings ...)
  2017-05-18 22:25 ` [PATCH v2 3/9] libsepol: Add Infiniband Pkey handling to CIL Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 5/9] libsepol: Add ibendport ocontext handling Dan Jurgens
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Add checkpolicy support for scanning and parsing ibendportcon labels.
Also create a new ocontext for IB end ports.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>

---
v1:
Stephen Smalley:
- Check IB device name length when parsing policy.
- Use strcmp vs strncmp to compare device names.

v2:
Stephen Smalley:
- Bound check port number when parsing ibendports.
---
 checkpolicy/policy_define.c                | 80 ++++++++++++++++++++++++++++++
 checkpolicy/policy_define.h                |  1 +
 checkpolicy/policy_parse.y                 | 14 +++++-
 checkpolicy/policy_scan.l                  |  2 +
 libsepol/include/sepol/policydb/policydb.h |  9 +++-
 5 files changed, 103 insertions(+), 3 deletions(-)

diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index e73ec8f7..f12ebdbd 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -5164,6 +5164,86 @@ out:
 	return rc;
 }
 
+int define_ibendport_context(unsigned int port)
+{
+	ocontext_t *newc, *c, *l, *head;
+	char *id;
+	int rc = 0;
+
+	if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
+		yyerror("ibendportcon not supported for target");
+		return -1;
+	}
+
+	if (pass == 1) {
+		id = (char *)queue_remove(id_queue);
+		free(id);
+		parse_security_context(NULL);
+		return 0;
+	}
+
+	if (port > 0xff || port == 0) {
+		yyerror("Invalid ibendport port number, should be 0 < port < 256");
+		return -1;
+	}
+
+	newc = malloc(sizeof(*newc));
+	if (!newc) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(newc, 0, sizeof(*newc));
+
+	newc->u.ibendport.dev_name = queue_remove(id_queue);
+	if (!newc->u.ibendport.dev_name) {
+		yyerror("failed to read infiniband device name.");
+		rc = -1;
+		goto out;
+	}
+
+	if (strlen(newc->u.ibendport.dev_name) > IB_DEVICE_NAME_MAX - 1) {
+		yyerror("infiniband device name exceeds max length of 63.");
+		rc = -1;
+		goto out;
+	}
+
+	newc->u.ibendport.port = port;
+
+	if (parse_security_context(&newc->context[0])) {
+		free(newc);
+		return -1;
+	}
+
+	/* Preserve the matching order specified in the configuration. */
+	head = policydbp->ocontexts[OCON_IBENDPORT];
+	for (l = NULL, c = head; c; l = c, c = c->next) {
+		unsigned int port2;
+
+		port2 = c->u.ibendport.port;
+
+		if (port == port2 &&
+		    !strcmp(c->u.ibendport.dev_name,
+			     newc->u.ibendport.dev_name)) {
+			yyerror2("duplicate ibendportcon entry for %s port %u",
+				 newc->u.ibendport.dev_name, port);
+			rc = -1;
+			goto out;
+		}
+	}
+
+	if (l)
+		l->next = newc;
+	else
+		policydbp->ocontexts[OCON_IBENDPORT] = newc;
+
+	return 0;
+
+out:
+	free(newc->u.ibendport.dev_name);
+	free(newc);
+	return rc;
+}
+
 int define_netif_context(void)
 {
 	ocontext_t *newc, *c, *head;
diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h
index 75e3683b..50a7ba78 100644
--- a/checkpolicy/policy_define.h
+++ b/checkpolicy/policy_define.h
@@ -44,6 +44,7 @@ int define_netif_context(void);
 int define_permissive(void);
 int define_polcap(void);
 int define_ibpkey_context(unsigned int low, unsigned int high);
+int define_ibendport_context(unsigned int port);
 int define_port_context(unsigned int low, unsigned int high);
 int define_pirq_context(unsigned int pirq);
 int define_iomem_context(uint64_t low, uint64_t high);
diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y
index 35b433bd..6b406c85 100644
--- a/checkpolicy/policy_parse.y
+++ b/checkpolicy/policy_parse.y
@@ -137,6 +137,7 @@ typedef int (* require_func_t)(int pass);
 %token SAMEUSER
 %token FSCON PORTCON NETIFCON NODECON 
 %token IBPKEYCON
+%token IBENDPORTCON
 %token PIRQCON IOMEMCON IOPORTCON PCIDEVICECON DEVICETREECON
 %token FSUSEXATTR FSUSETASK FSUSETRANS
 %token GENFSCON
@@ -172,7 +173,7 @@ base_policy             : { if (define_policy(pass, 0) == -1) return -1; }
 			  opt_default_rules opt_mls te_rbac users opt_constraints 
                          { if (pass == 1) { if (policydb_index_bools(policydbp)) return -1;}
 			   else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1;}}
-			  initial_sid_contexts opt_fs_contexts opt_fs_uses opt_genfs_contexts net_contexts opt_dev_contexts opt_ibpkey_contexts
+			  initial_sid_contexts opt_fs_contexts opt_fs_uses opt_genfs_contexts net_contexts opt_dev_contexts opt_ibpkey_contexts opt_ibendport_contexts
 			;
 classes			: class_def 
 			| classes class_def
@@ -702,7 +703,7 @@ fs_contexts		: fs_context_def
 fs_context_def		: FSCON number number security_context_def security_context_def
 			{if (define_fs_context($2,$3)) return -1;}
 			;
-net_contexts		: opt_port_contexts opt_netif_contexts opt_node_contexts 
+net_contexts		: opt_port_contexts opt_netif_contexts opt_node_contexts
 			;
 opt_port_contexts       : port_contexts
                         |
@@ -726,6 +727,15 @@ ibpkey_context_def	: IBPKEYCON ipv6_addr number security_context_def
 			| IBPKEYCON ipv6_addr number '-' number security_context_def
 			{if (define_ibpkey_context($3,$5)) return -1;}
 			;
+opt_ibendport_contexts	: ibendport_contexts
+			|
+			;
+ibendport_contexts	: ibendport_context_def
+                        | ibendport_contexts ibendport_context_def
+                        ;
+ibendport_context_def	: IBENDPORTCON identifier number security_context_def
+                        {if (define_ibendport_context($3)) return -1;}
+                        ;
 opt_netif_contexts      : netif_contexts 
                         |
                         ;
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index f742939a..e6c48984 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -186,6 +186,8 @@ fscon |
 FSCON                           { return(FSCON);}
 ibpkeycon |
 IBPKEYCON			{ return(IBPKEYCON);}
+ibendportcon |
+IBENDPORTCON			{ return(IBENDPORTCON);}
 portcon |
 PORTCON				{ return(PORTCON);}
 netifcon |                     
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index d06d2153..1b2d7820 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -73,6 +73,8 @@
 extern "C" {
 #endif
 
+#define IB_DEVICE_NAME_MAX 64
+
 /*
  * A datum type is defined for each kind of symbol 
  * in the configuration data:  individual permissions, 
@@ -364,6 +366,10 @@ typedef struct ocontext {
 			uint16_t low_pkey;
 			uint16_t high_pkey;
 		} ibpkey;
+		struct {
+			char *dev_name;
+			uint8_t port;
+		} ibendport;
 	} u;
 	union {
 		uint32_t sclass;	/* security class for genfs */
@@ -400,6 +406,7 @@ typedef struct genfs {
 #define OCON_FSUSE 5	/* fs_use */
 #define OCON_NODE6 6	/* IPv6 nodes */
 #define OCON_IBPKEY 7	/* Infiniband PKEY */
+#define OCON_IBENDPORT 8	/* Infiniband End Port */
 
 /* object context array indices for Xen */
 #define OCON_XEN_ISID  	    0    /* initial SIDs */
@@ -410,7 +417,7 @@ typedef struct genfs {
 #define OCON_XEN_DEVICETREE 5    /* device tree node */
 
 /* OCON_NUM needs to be the largest index in any platform's ocontext array */
-#define OCON_NUM   8
+#define OCON_NUM   9
 
 /* section: module information */
 
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 5/9] libsepol: Add ibendport ocontext handling
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
                   ` (3 preceding siblings ...)
  2017-05-18 22:25 ` [PATCH v2 4/9] checkpolicy: Add support for ibendportcon labels Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 6/9] libsepol: Add IB end port handling to CIL Dan Jurgens
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Add support for reading, writing, and copying IB end port ocontext data.
Also add support for querying a IB end port sid to checkpolicy.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>

---
v1:
Stephen Smalley:
- Removed unused domain and type params from sepol_ibendport_sid.
- Remove ibendport initial sid from ocontext_selinux_isid_to_cil
- Check the length provide for the device name in ocontext_read_selinux
- Used strcmp for dev_name comparison.

James Carter:
- Added ibendport handling to kernel_to_cil.c and kernel_to_conf.c

v2:
James Carter
- Sort ocontexts in kernel_to_common.c
---
 checkpolicy/checkpolicy.c                  | 20 ++++++++++++++
 libsepol/include/sepol/policydb/services.h |  8 ++++++
 libsepol/src/expand.c                      |  8 ++++++
 libsepol/src/kernel_to_cil.c               | 42 ++++++++++++++++++++++++++++++
 libsepol/src/kernel_to_common.c            | 18 +++++++++++++
 libsepol/src/kernel_to_conf.c              | 41 +++++++++++++++++++++++++++++
 libsepol/src/libsepol.map.in               |  1 +
 libsepol/src/module_to_cil.c               | 14 ++++++++++
 libsepol/src/policydb.c                    | 26 +++++++++++++++---
 libsepol/src/services.c                    | 37 ++++++++++++++++++++++++++
 libsepol/src/write.c                       | 14 ++++++++++
 11 files changed, 226 insertions(+), 3 deletions(-)

diff --git a/checkpolicy/checkpolicy.c b/checkpolicy/checkpolicy.c
index 8aeecc1b..b75f2afa 100644
--- a/checkpolicy/checkpolicy.c
+++ b/checkpolicy/checkpolicy.c
@@ -701,6 +701,7 @@ int main(int argc, char **argv)
 	printf("i)  display constraint expressions\n");
 	printf("j)  display validatetrans expressions\n");
 	printf("k)  Call ibpkey_sid\n");
+	printf("l)  Call ibendport_sid\n");
 #ifdef EQUIVTYPES
 	printf("z)  Show equivalent types\n");
 #endif
@@ -1247,6 +1248,25 @@ int main(int argc, char **argv)
 				printf("sid %d\n", ssid);
 			}
 			break;
+		case 'l':
+			printf("device name (eg. mlx4_0)?  ");
+			FGETS(ans, sizeof(ans), stdin);
+			ans[strlen(ans) - 1] = 0;
+
+			name = malloc((strlen(ans) + 1) * sizeof(char));
+			if (!name) {
+				fprintf(stderr, "couldn't malloc string.\n");
+				break;
+			}
+			strcpy(name, ans);
+
+			printf("port? ");
+			FGETS(ans, sizeof(ans), stdin);
+			port = atoi(ans);
+			sepol_ibendport_sid(name, port, &ssid);
+			printf("sid %d\n", ssid);
+			free(name);
+			break;
 #ifdef EQUIVTYPES
 		case 'z':
 			identify_equiv_types();
diff --git a/libsepol/include/sepol/policydb/services.h b/libsepol/include/sepol/policydb/services.h
index 3f3b95d1..efdf7de5 100644
--- a/libsepol/include/sepol/policydb/services.h
+++ b/libsepol/include/sepol/policydb/services.h
@@ -196,6 +196,14 @@ extern int sepol_ibpkey_sid(uint64_t subnet_prefix_p,
 			    sepol_security_id_t *out_sid);
 
 /*
+ * Return the SID of the ibendport specified by
+ * `dev_name', and `port'.
+ */
+extern int sepol_ibendport_sid(char *dev_name,
+			       uint8_t port,
+			       sepol_security_id_t *out_sid);
+
+/*
  * Return the SIDs to use for a network interface
  * with the name `name'.  The `if_sid' SID is returned for 
  * the interface and the `msg_sid' SID is returned as
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index e4cfc41e..8f7a25d8 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -2224,6 +2224,14 @@ static int ocontext_copy_selinux(expand_state_t *state)
 				n->u.ibpkey.low_pkey = c->u.ibpkey.low_pkey;
 				n->u.ibpkey.high_pkey = c->u.ibpkey.high_pkey;
 			break;
+			case OCON_IBENDPORT:
+				n->u.ibendport.dev_name = strdup(c->u.ibendport.dev_name);
+				if (!n->u.ibendport.dev_name) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				n->u.ibendport.port = c->u.ibendport.port;
+				break;
 			case OCON_PORT:
 				n->u.port.protocol = c->u.port.protocol;
 				n->u.port.low_port = c->u.port.low_port;
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index d1006186..f4ec8832 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -2841,6 +2841,43 @@ exit:
 	return rc;
 }
 
+static int write_selinux_ibendport_rules_to_cil(FILE *out, struct policydb *pdb)
+{
+	struct ocontext *ibendportcon;
+	char port_str[4];
+	char *ctx;
+	int rc = 0;
+
+	for (ibendportcon = pdb->ocontexts[OCON_IBENDPORT];
+	     ibendportcon != NULL; ibendportcon = ibendportcon->next) {
+		rc = snprintf(port_str, 4, "%u", ibendportcon->u.ibendport.port);
+		if (rc < 0 || rc >= 4) {
+			rc = -1;
+			goto exit;
+		}
+
+		ctx = context_to_str(pdb, &ibendportcon->context[0]);
+		if (!ctx) {
+			rc = -1;
+			goto exit;
+		}
+
+		sepol_printf(out, "(ibendportcon %s %s %s)\n",
+			     ibendportcon->u.ibendport.dev_name, port_str, ctx);
+
+		free(ctx);
+	}
+
+	rc = 0;
+
+exit:
+	if (rc != 0) {
+		sepol_log_err("Error writing ibendportcon rules to CIL\n");
+	}
+
+	return rc;
+}
+
 static int write_xen_isid_rules_to_cil(FILE *out, struct policydb *pdb)
 {
 	return write_sid_context_rules_to_cil(out, pdb, xen_sid_to_str);
@@ -3242,6 +3279,11 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb)
 		if (rc != 0) {
 			goto exit;
 		}
+
+		rc = write_selinux_ibendport_rules_to_cil(out, pdb);
+		if (rc != 0) {
+			goto exit;
+		}
 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
 		rc = write_xen_isid_rules_to_cil(out, pdb);
 		if (rc != 0) {
diff --git a/libsepol/src/kernel_to_common.c b/libsepol/src/kernel_to_common.c
index 294f0b4e..01ffc8fc 100644
--- a/libsepol/src/kernel_to_common.c
+++ b/libsepol/src/kernel_to_common.c
@@ -532,6 +532,19 @@ static int ibpkey_data_cmp(const void *a, const void *b)
 			      (*bb)->u.ibpkey.low_pkey, (*bb)->u.ibpkey.high_pkey);
 }
 
+static int ibendport_data_cmp(const void *a, const void *b)
+{
+	int rc;
+	struct ocontext *const *aa = a;
+	struct ocontext *const *bb = b;
+
+	rc = strcmp((*aa)->u.ibendport.dev_name, (*bb)->u.ibendport.dev_name);
+	if (rc)
+		return rc;
+
+	return (*aa)->u.ibendport.port - (*bb)->u.ibendport.port;
+}
+
 static int pirq_data_cmp(const void *a, const void *b)
 {
 	struct ocontext *const *aa = a;
@@ -660,6 +673,11 @@ int sort_ocontexts(struct policydb *pdb)
 		if (rc != 0) {
 			goto exit;
 		}
+
+		rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBENDPORT], ibendport_data_cmp);
+		if (rc != 0) {
+			goto exit;
+		}
 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
 		rc = sort_ocontext_data(&pdb->ocontexts[1], pirq_data_cmp);
 		if (rc != 0) {
diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index 23307ce6..a74873f0 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -2703,6 +2703,42 @@ exit:
 	return rc;
 }
 
+static int write_selinux_ibendport_rules_to_conf(FILE *out, struct policydb *pdb)
+{
+	struct ocontext *ibendportcon;
+	char port_str[4];
+	char *ctx;
+	int rc = 0;
+
+	for (ibendportcon = pdb->ocontexts[OCON_IBENDPORT];
+	     ibendportcon != NULL; ibendportcon = ibendportcon->next) {
+		rc = snprintf(port_str, 4, "%u", ibendportcon->u.ibendport.port);
+		if (rc < 0 || rc >= 4) {
+			rc = -1;
+			goto exit;
+		}
+
+		ctx = context_to_str(pdb, &ibendportcon->context[0]);
+		if (!ctx) {
+			rc = -1;
+			goto exit;
+		}
+
+		sepol_printf(out, "ibendportcon %s %s %s\n", ibendportcon->u.ibendport.dev_name, port_str, ctx);
+
+		free(ctx);
+	}
+
+	rc = 0;
+
+exit:
+	if (rc != 0) {
+		sepol_log_err("Error writing ibendportcon rules to policy.conf\n");
+	}
+
+	return rc;
+}
+
 static int write_xen_isid_rules_to_conf(FILE *out, struct policydb *pdb)
 {
 	return write_sid_context_rules_to_conf(out, pdb, xen_sid_to_str);
@@ -3108,6 +3144,11 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
 		if (rc != 0) {
 			goto exit;
 		}
+
+		rc = write_selinux_ibendport_rules_to_conf(out, pdb);
+		if (rc != 0) {
+			goto exit;
+		}
 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
 		rc = write_xen_isid_rules_to_conf(out, pdb);
 		if (rc != 0) {
diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in
index 36225d1c..dd1fec21 100644
--- a/libsepol/src/libsepol.map.in
+++ b/libsepol/src/libsepol.map.in
@@ -7,6 +7,7 @@ LIBSEPOL_1.0 {
 	sepol_iface_*; 
 	sepol_port_*;
 	sepol_ibpkey_*;
+	sepol_ibendport_*;
 	sepol_node_*;
 	sepol_user_*; sepol_genusers; sepol_set_delusers;
 	sepol_msg_*; sepol_debug;
diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
index 10d0700c..41f0d6ce 100644
--- a/libsepol/src/module_to_cil.c
+++ b/libsepol/src/module_to_cil.c
@@ -2776,6 +2776,19 @@ exit:
 	return rc;
 }
 
+static int ocontext_selinux_ibendport_to_cil(struct policydb *pdb, struct ocontext *ibendports)
+{
+	struct ocontext *ibendport;
+
+	for (ibendport = ibendports; ibendport; ibendport = ibendport->next) {
+		cil_printf("(ibendportcon %s %u ", ibendport->u.ibendport.dev_name, ibendport->u.ibendport.port);
+		context_to_cil(pdb, &ibendport->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
 
 static int ocontext_selinux_fsuse_to_cil(struct policydb *pdb, struct ocontext *fsuses)
 {
@@ -2930,6 +2943,7 @@ static int ocontexts_to_cil(struct policydb *pdb)
 		ocontext_selinux_fsuse_to_cil,
 		ocontext_selinux_node6_to_cil,
 		ocontext_selinux_ibpkey_to_cil,
+		ocontext_selinux_ibendport_to_cil,
 	};
 	static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
 		ocontext_xen_isid_to_cil,
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 09d14140..ab3b31f7 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -190,7 +190,7 @@ static struct policydb_compat_info policydb_compat[] = {
 	 .type = POLICY_KERN,
 	 .version = POLICYDB_VERSION_INFINIBAND,
 	 .sym_num = SYM_NUM,
-	 .ocon_num = OCON_IBPKEY + 1,
+	 .ocon_num = OCON_IBENDPORT + 1,
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
 	{
@@ -302,7 +302,7 @@ static struct policydb_compat_info policydb_compat[] = {
 	 .type = POLICY_BASE,
 	 .version = MOD_POLICYDB_VERSION_INFINIBAND,
 	 .sym_num = SYM_NUM,
-	 .ocon_num = OCON_IBPKEY + 1,
+	 .ocon_num = OCON_IBENDPORT + 1,
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
 	{
@@ -2804,7 +2804,7 @@ static int ocontext_read_selinux(struct policydb_compat_info *info,
 				if (rc < 0)
 					return -1;
 				len = le32_to_cpu(buf[0]);
-				if (zero_or_saturated(len))
+				if (zero_or_saturated(len) || len > 63)
 					return -1;
 				c->u.name = malloc(len + 1);
 				if (!c->u.name)
@@ -2835,6 +2835,26 @@ static int ocontext_read_selinux(struct policydb_compat_info *info,
 				    (&c->context[0], p, fp))
 					return -1;
 				break;
+			case OCON_IBENDPORT:
+				rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+				if (rc < 0)
+					return -1;
+				len = le32_to_cpu(buf[0]);
+				if (len == 0 || len > IB_DEVICE_NAME_MAX - 1)
+					return -1;
+
+				c->u.ibendport.dev_name = malloc(len + 1);
+				if (!c->u.ibendport.dev_name)
+					return -1;
+				rc = next_entry(c->u.ibendport.dev_name, fp, len);
+				if (rc < 0)
+					return -1;
+				c->u.ibendport.dev_name[len] = 0;
+				c->u.ibendport.port = le32_to_cpu(buf[1]);
+				if (context_read_and_validate
+				    (&c->context[0], p, fp))
+					return -1;
+				break;
 			case OCON_PORT:
 				rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
 				if (rc < 0)
diff --git a/libsepol/src/services.c b/libsepol/src/services.c
index 27e802c6..10338a65 100644
--- a/libsepol/src/services.c
+++ b/libsepol/src/services.c
@@ -1948,6 +1948,43 @@ out:
 }
 
 /*
+ * Return the SID of the subnet management interface specified by
+ * `device name', and `port'.
+ */
+int hidden sepol_ibendport_sid(char *dev_name,
+			       uint8_t port,
+			       sepol_security_id_t *out_sid)
+{
+	ocontext_t *c;
+	int rc = 0;
+
+	c = policydb->ocontexts[OCON_IBENDPORT];
+	while (c) {
+		if (c->u.ibendport.port == port &&
+		    !strcmp(dev_name, c->u.ibendport.dev_name))
+			break;
+		c = c->next;
+	}
+
+	if (c) {
+		if (!c->sid[0]) {
+			rc = sepol_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:
+	return rc;
+}
+
+
+/*
  * Return the SID of the port specified by
  * `domain', `type', `protocol', and `port'.
  */
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index f63e7489..e486e286 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -1427,6 +1427,20 @@ static int ocontext_write_selinux(struct policydb_compat_info *info,
 				if (context_write(p, &c->context[0], fp))
 					return POLICYDB_ERROR;
 				break;
+			case OCON_IBENDPORT:
+				len = strlen(c->u.ibendport.dev_name);
+				buf[0] = cpu_to_le32(len);
+				buf[1] = cpu_to_le32(c->u.ibendport.port);
+				items = put_entry(buf, sizeof(uint32_t), 2, fp);
+				if (items != 2)
+					return POLICYDB_ERROR;
+				items = put_entry(c->u.ibendport.dev_name, 1, len, fp);
+				if (items != len)
+					return POLICYDB_ERROR;
+
+				if (context_write(p, &c->context[0], fp))
+					return POLICYDB_ERROR;
+				break;
 			case OCON_PORT:
 				buf[0] = c->u.port.protocol;
 				buf[1] = c->u.port.low_port;
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 6/9] libsepol: Add IB end port handling to CIL
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
                   ` (4 preceding siblings ...)
  2017-05-18 22:25 ` [PATCH v2 5/9] libsepol: Add ibendport ocontext handling Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 7/9] semanage: Update semanage to allow runtime labeling of Infiniband Pkeys Dan Jurgens
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Add IB end port parsing, symbol table management, and policy generation
to CIL.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>

---
v1:
James Carter:
- Add cil_resolve_ibendportcon prototype in cil_resolve_ast.h
---
 libsepol/cil/src/cil.c             | 18 +++++++++++
 libsepol/cil/src/cil_binary.c      | 29 +++++++++++++++++
 libsepol/cil/src/cil_binary.h      | 12 +++++++
 libsepol/cil/src/cil_build_ast.c   | 65 ++++++++++++++++++++++++++++++++++++++
 libsepol/cil/src/cil_build_ast.h   |  2 ++
 libsepol/cil/src/cil_copy_ast.c    | 25 +++++++++++++++
 libsepol/cil/src/cil_flavor.h      |  1 +
 libsepol/cil/src/cil_internal.h    |  9 ++++++
 libsepol/cil/src/cil_policy.c      | 15 +++++++++
 libsepol/cil/src/cil_post.c        | 42 ++++++++++++++++++++++++
 libsepol/cil/src/cil_post.h        |  1 +
 libsepol/cil/src/cil_reset_ast.c   | 10 ++++++
 libsepol/cil/src/cil_resolve_ast.c | 28 ++++++++++++++++
 libsepol/cil/src/cil_resolve_ast.h |  1 +
 libsepol/cil/src/cil_tree.c        | 13 ++++++++
 libsepol/cil/src/cil_verify.c      | 23 ++++++++++++++
 16 files changed, 294 insertions(+)

diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
index 3df670a7..c02a41a5 100644
--- a/libsepol/cil/src/cil.c
+++ b/libsepol/cil/src/cil.c
@@ -189,6 +189,7 @@ static void cil_init_keys(void)
 	CIL_KEY_CONTEXT = cil_strpool_add("context");
 	CIL_KEY_FILECON = cil_strpool_add("filecon");
 	CIL_KEY_IBPKEYCON = cil_strpool_add("ibpkeycon");
+	CIL_KEY_IBENDPORTCON = cil_strpool_add("ibendportcon");
 	CIL_KEY_PORTCON = cil_strpool_add("portcon");
 	CIL_KEY_NODECON = cil_strpool_add("nodecon");
 	CIL_KEY_GENFSCON = cil_strpool_add("genfscon");
@@ -259,6 +260,7 @@ void cil_db_init(struct cil_db **db)
 	cil_sort_init(&(*db)->filecon);
 	cil_sort_init(&(*db)->nodecon);
 	cil_sort_init(&(*db)->ibpkeycon);
+	cil_sort_init(&(*db)->ibendportcon);
 	cil_sort_init(&(*db)->portcon);
 	cil_sort_init(&(*db)->pirqcon);
 	cil_sort_init(&(*db)->iomemcon);
@@ -311,6 +313,7 @@ void cil_db_destroy(struct cil_db **db)
 	cil_sort_destroy(&(*db)->filecon);
 	cil_sort_destroy(&(*db)->nodecon);
 	cil_sort_destroy(&(*db)->ibpkeycon);
+	cil_sort_destroy(&(*db)->ibendportcon);
 	cil_sort_destroy(&(*db)->portcon);
 	cil_sort_destroy(&(*db)->pirqcon);
 	cil_sort_destroy(&(*db)->iomemcon);
@@ -737,6 +740,9 @@ void cil_destroy_data(void **data, enum cil_flavor flavor)
 	case CIL_PORTCON:
 		cil_destroy_portcon(*data);
 		break;
+	case CIL_IBENDPORTCON:
+		cil_destroy_ibendportcon(*data);
+		break;
 	case CIL_NODECON:
 		cil_destroy_nodecon(*data);
 		break;
@@ -1105,6 +1111,8 @@ const char * cil_node_to_string(struct cil_tree_node *node)
 		return CIL_KEY_FILECON;
 	case CIL_IBPKEYCON:
 		return CIL_KEY_IBPKEYCON;
+	case CIL_IBENDPORTCON:
+		return CIL_KEY_IBENDPORTCON;
 	case CIL_PORTCON:
 		return CIL_KEY_PORTCON;
 	case CIL_NODECON:
@@ -1838,6 +1846,16 @@ void cil_netifcon_init(struct cil_netifcon **netifcon)
 	(*netifcon)->context_str = NULL;
 }
 
+void cil_ibendportcon_init(struct cil_ibendportcon **ibendportcon)
+{
+	*ibendportcon = cil_malloc(sizeof(**ibendportcon));
+
+	(*ibendportcon)->dev_name_str = NULL;
+	(*ibendportcon)->port = 0;
+	(*ibendportcon)->context_str = NULL;
+	(*ibendportcon)->context = NULL;
+}
+
 void cil_context_init(struct cil_context **context)
 {
 	*context = cil_malloc(sizeof(**context));
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index 1ddbf21f..c0ca60f2 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -3323,6 +3323,30 @@ exit:
 	return rc;
 }
 
+int cil_ibendportcon_to_policydb(policydb_t *pdb, struct cil_sort *ibendportcons)
+{
+	int rc = SEPOL_ERR;
+	uint32_t i;
+	ocontext_t *tail = NULL;
+
+	for (i = 0; i < ibendportcons->count; i++) {
+		ocontext_t *new_ocon = cil_add_ocontext(&pdb->ocontexts[OCON_IBENDPORT], &tail);
+		struct cil_ibendportcon *cil_ibendportcon = ibendportcons->array[i];
+
+		new_ocon->u.ibendport.dev_name = cil_strdup(cil_ibendportcon->dev_name_str);
+		new_ocon->u.ibendport.port = cil_ibendportcon->port;
+
+		rc = __cil_context_to_sepol_context(pdb, cil_ibendportcon->context, &new_ocon->context[0]);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
 int cil_nodecon_to_policydb(policydb_t *pdb, struct cil_sort *nodecons)
 {
 	int rc = SEPOL_ERR;
@@ -3887,6 +3911,11 @@ int __cil_contexts_to_policydb(policydb_t *pdb, const struct cil_db *db)
 		goto exit;
 	}
 
+	rc = cil_ibendportcon_to_policydb(pdb, db->ibendportcon);
+	if (rc != SEPOL_OK) {
+		goto exit;
+	}
+
 	if (db->target_platform == SEPOL_TARGET_XEN) {
 		rc = cil_pirqcon_to_policydb(pdb, db->pirqcon);
 		if (rc != SEPOL_OK) {
diff --git a/libsepol/cil/src/cil_binary.h b/libsepol/cil/src/cil_binary.h
index a03d250d..5367febe 100644
--- a/libsepol/cil/src/cil_binary.h
+++ b/libsepol/cil/src/cil_binary.h
@@ -342,6 +342,18 @@ int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, st
 int cil_ibpkeycon_to_policydb(policydb_t *pdb, struct cil_sort *ibpkeycons);
 
 /**
+ * Insert cil idbev structure into sepol policydb.
+ * The function is given a structure containing the sorted ibendportcons and
+ * loops over this structure inserting them into the policy database.
+ *
+ * @param[in] pdb The policy database to insert the pkeycon into.
+ * @param[in] node The cil_sort structure that contains the sorted ibendportcons.
+ *
+ * @return SEPOL_OK upon success or an error otherwise.
+ */
+int cil_ibendportcon_to_policydb(policydb_t *pdb, struct cil_sort *pkeycons);
+
+/**
  * Insert cil portcon structure into sepol policydb.
  * The function is given a structure containing the sorted portcons and
  * loops over this structure inserting them into the policy database.
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
index 11215744..0a9a5e57 100644
--- a/libsepol/cil/src/cil_build_ast.c
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -4667,6 +4667,68 @@ void cil_destroy_netifcon(struct cil_netifcon *netifcon)
 	free(netifcon);
 }
 
+int cil_gen_ibendportcon(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
+{
+	enum cil_syntax syntax[] = {
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING,
+		CIL_SYN_STRING | CIL_SYN_LIST,
+		CIL_SYN_END
+	};
+	int syntax_len = sizeof(syntax) / sizeof(*syntax);
+	int rc = SEPOL_ERR;
+	struct cil_ibendportcon *ibendportcon = NULL;
+
+	if (!db || !parse_current || !ast_node)
+		goto exit;
+
+	rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
+	if (rc != SEPOL_OK)
+		goto exit;
+
+	cil_ibendportcon_init(&ibendportcon);
+
+	ibendportcon->dev_name_str = parse_current->next->data;
+
+	rc = cil_fill_integer(parse_current->next->next, &ibendportcon->port, 10);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Improper ibendport port specified\n");
+		goto exit;
+	}
+
+	if (!parse_current->next->next->next->cl_head) {
+		ibendportcon->context_str = parse_current->next->next->data;
+	} else {
+		cil_context_init(&ibendportcon->context);
+
+		rc = cil_fill_context(parse_current->next->next->next->cl_head, ibendportcon->context);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	ast_node->data = ibendportcon;
+	ast_node->flavor = CIL_IBENDPORTCON;
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(parse_current, CIL_ERR, "Bad ibendportcon declaration");
+	cil_destroy_ibendportcon(ibendportcon);
+	return SEPOL_ERR;
+}
+
+void cil_destroy_ibendportcon(struct cil_ibendportcon *ibendportcon)
+{
+	if (!ibendportcon)
+		return;
+
+	if (!ibendportcon->context_str && ibendportcon->context)
+		cil_destroy_context(ibendportcon->context);
+
+	free(ibendportcon);
+}
+
 int cil_gen_pirqcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
 {
 	enum cil_syntax syntax[] = {
@@ -6301,6 +6363,9 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
 	} else if (parse_current->data == CIL_KEY_IBPKEYCON) {
 		rc = cil_gen_ibpkeycon(db, parse_current, ast_node);
 		*finished = CIL_TREE_SKIP_NEXT;
+	} else if (parse_current->data == CIL_KEY_IBENDPORTCON) {
+		rc = cil_gen_ibendportcon(db, parse_current, ast_node);
+		*finished = CIL_TREE_SKIP_NEXT;
 	} else if (parse_current->data == CIL_KEY_PORTCON) {
 		rc = cil_gen_portcon(db, parse_current, ast_node);
 		*finished = CIL_TREE_SKIP_NEXT;
diff --git a/libsepol/cil/src/cil_build_ast.h b/libsepol/cil/src/cil_build_ast.h
index c2d7b31e..8153e51e 100644
--- a/libsepol/cil/src/cil_build_ast.h
+++ b/libsepol/cil/src/cil_build_ast.h
@@ -177,6 +177,8 @@ int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, stru
 void cil_destroy_filecon(struct cil_filecon *filecon);
 int cil_gen_ibpkeycon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
 void cil_destroy_ibpkeycon(struct cil_ibpkeycon *ibpkeycon);
+int cil_gen_ibendportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
+void cil_destroy_ibendportcon(struct cil_ibendportcon *ibendportcon);
 int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
 void cil_destroy_portcon(struct cil_portcon *portcon);
 int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
index 7307b08b..7af00aaf 100644
--- a/libsepol/cil/src/cil_copy_ast.c
+++ b/libsepol/cil/src/cil_copy_ast.c
@@ -1227,6 +1227,28 @@ int cil_copy_ibpkeycon(struct cil_db *db, void *data, void **copy, __attribute__
 	return SEPOL_OK;
 }
 
+int cil_copy_ibendportcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
+{
+	struct cil_ibendportcon *orig = data;
+	struct cil_ibendportcon *new = NULL;
+
+	cil_ibendportcon_init(&new);
+
+	new->dev_name_str = orig->dev_name_str;
+	new->port = orig->port;
+
+	if (orig->context_str) {
+		new->context_str = orig->context_str;
+	} else {
+		cil_context_init(&new->context);
+		cil_copy_fill_context(db, orig->context, new->context);
+	}
+
+	*copy = new;
+
+	return SEPOL_OK;
+}
+
 int cil_copy_portcon(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
 {
 	struct cil_portcon *orig = data;
@@ -1942,6 +1964,9 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u
 	case CIL_IBPKEYCON:
 		copy_func = &cil_copy_ibpkeycon;
 		break;
+	case CIL_IBENDPORTCON:
+		copy_func = &cil_copy_ibendportcon;
+		break;
 	case CIL_PORTCON:
 		copy_func = &cil_copy_portcon;
 		break;
diff --git a/libsepol/cil/src/cil_flavor.h b/libsepol/cil/src/cil_flavor.h
index 4505b8bb..c2f0cee7 100644
--- a/libsepol/cil/src/cil_flavor.h
+++ b/libsepol/cil/src/cil_flavor.h
@@ -114,6 +114,7 @@ enum cil_flavor {
 	CIL_MLS,
 	CIL_SRC_INFO,
 	CIL_IBPKEYCON,
+	CIL_IBENDPORTCON,
 
 /*
  *          boolean  constraint  set  catset
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
index 2add97bb..6d6a7d90 100644
--- a/libsepol/cil/src/cil_internal.h
+++ b/libsepol/cil/src/cil_internal.h
@@ -204,6 +204,7 @@ char *CIL_KEY_MLSVALIDATETRANS;
 char *CIL_KEY_CONTEXT;
 char *CIL_KEY_FILECON;
 char *CIL_KEY_IBPKEYCON;
+char *CIL_KEY_IBENDPORTCON;
 char *CIL_KEY_PORTCON;
 char *CIL_KEY_NODECON;
 char *CIL_KEY_GENFSCON;
@@ -288,6 +289,7 @@ struct cil_db {
 	struct cil_sort *filecon;
 	struct cil_sort *nodecon;
 	struct cil_sort *ibpkeycon;
+	struct cil_sort *ibendportcon;
 	struct cil_sort *portcon;
 	struct cil_sort *pirqcon;
 	struct cil_sort *iomemcon;
@@ -789,6 +791,12 @@ struct cil_netifcon {
 	char *context_str;
 };
 
+struct cil_ibendportcon {
+	char *dev_name_str;
+	uint32_t port;
+	char *context_str;
+	struct cil_context *context;
+};
 struct cil_pirqcon {
 	uint32_t pirq;
 	char *context_str;
@@ -974,6 +982,7 @@ int cil_get_symtab(struct cil_tree_node *ast_node, symtab_t **symtab, enum cil_s
 void cil_sort_init(struct cil_sort **sort);
 void cil_sort_destroy(struct cil_sort **sort);
 void cil_netifcon_init(struct cil_netifcon **netifcon);
+void cil_ibendportcon_init(struct cil_ibendportcon **ibendportcon);
 void cil_context_init(struct cil_context **context);
 void cil_level_init(struct cil_level **level);
 void cil_levelrange_init(struct cil_levelrange **lvlrange);
diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
index 35a0a29e..2196ae8d 100644
--- a/libsepol/cil/src/cil_policy.c
+++ b/libsepol/cil/src/cil_policy.c
@@ -1729,6 +1729,20 @@ static void cil_ibpkeycons_to_policy(FILE *out, struct cil_sort *ibpkeycons, int
 	}
 }
 
+static void cil_ibendportcons_to_policy(FILE *out, struct cil_sort *ibendportcons, int mls)
+{
+	uint32_t i;
+
+	for (i = 0; i < ibendportcons->count; i++) {
+		struct cil_ibendportcon *ibendportcon = (struct cil_ibendportcon *)ibendportcons->array[i];
+
+		fprintf(out, "ibendportcon %s ", ibendportcon->dev_name_str);
+		fprintf(out, "%u ", ibendportcon->port);
+		cil_context_to_policy(out, ibendportcon->context, mls);
+		fprintf(out, "\n");
+	}
+}
+
 static void cil_portcons_to_policy(FILE *out, struct cil_sort *portcons, int mls)
 {
 	unsigned i;
@@ -1958,6 +1972,7 @@ void cil_gen_policy(FILE *out, struct cil_db *db)
 	cil_portcons_to_policy(out, db->portcon, db->mls);
 	cil_netifcons_to_policy(out, db->netifcon, db->mls);
 	cil_ibpkeycons_to_policy(out, db->ibpkeycon, db->mls);
+	cil_ibendportcons_to_policy(out, db->ibendportcon, db->mls);
 	cil_nodecons_to_policy(out, db->nodecon, db->mls);
 	cil_pirqcons_to_policy(out, db->pirqcon, db->mls);
 	cil_iomemcons_to_policy(out, db->iomemcon, db->mls);
diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
index 893860d5..0d494ea6 100644
--- a/libsepol/cil/src/cil_post.c
+++ b/libsepol/cil/src/cil_post.c
@@ -217,6 +217,25 @@ int cil_post_netifcon_compare(const void *a, const void *b)
 	return  strcmp(anetifcon->interface_str, bnetifcon->interface_str);
 }
 
+int cil_post_ibendportcon_compare(const void *a, const void *b)
+{
+	int rc = SEPOL_ERR;
+
+	struct cil_ibendportcon *aibendportcon = *(struct cil_ibendportcon **)a;
+	struct cil_ibendportcon *bibendportcon = *(struct cil_ibendportcon **)b;
+
+	rc = strcmp(aibendportcon->dev_name_str, bibendportcon->dev_name_str);
+	if (rc)
+		return rc;
+
+	if (aibendportcon->port < bibendportcon->port)
+		return -1;
+	else if (bibendportcon->port < aibendportcon->port)
+		return 1;
+
+	return rc;
+}
+
 int cil_post_nodecon_compare(const void *a, const void *b)
 {
 	struct cil_nodecon *anodecon;
@@ -426,6 +445,9 @@ static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *fini
 	case CIL_IBPKEYCON:
 		db->ibpkeycon->count++;
 		break;
+	case CIL_IBENDPORTCON:
+		db->ibendportcon->count++;
+		break;
 	case CIL_PORTCON:
 		db->portcon->count++;
 		break;
@@ -516,6 +538,17 @@ static int __cil_post_db_array_helper(struct cil_tree_node *node, uint32_t *fini
 		sort->index++;
 		break;
 	}
+	case CIL_IBENDPORTCON: {
+		struct cil_sort *sort = db->ibendportcon;
+		uint32_t count = sort->count;
+		uint32_t i = sort->index;
+
+		if (!sort->array)
+			sort->array = cil_malloc(sizeof(*sort->array) * count);
+		sort->array[i] = node->data;
+		sort->index++;
+		break;
+	}
 	case CIL_FSUSE: {
 		struct cil_sort *sort = db->fsuse;
 		uint32_t count = sort->count;
@@ -1662,6 +1695,14 @@ static int __cil_post_db_cat_helper(struct cil_tree_node *node, uint32_t *finish
 			goto exit;
 		break;
 	}
+	case CIL_IBENDPORTCON: {
+		struct cil_ibendportcon *ibendportcon = node->data;
+
+		rc = __evaluate_levelrange_expression(ibendportcon->context->range, db);
+		if (rc != SEPOL_OK)
+			goto exit;
+		break;
+	}
 	case CIL_PORTCON: {
 		struct cil_portcon *portcon = node->data;
 		rc = __evaluate_levelrange_expression(portcon->context->range, db);
@@ -2022,6 +2063,7 @@ static int cil_post_db(struct cil_db *db)
 	qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
 	qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
 	qsort(db->ibpkeycon->array, db->ibpkeycon->count, sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
+	qsort(db->ibendportcon->array, db->ibendportcon->count, sizeof(db->ibendportcon->array), cil_post_ibendportcon_compare);
 	qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
 	qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
 	qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
diff --git a/libsepol/cil/src/cil_post.h b/libsepol/cil/src/cil_post.h
index fe7f3a58..3d541548 100644
--- a/libsepol/cil/src/cil_post.h
+++ b/libsepol/cil/src/cil_post.h
@@ -40,6 +40,7 @@ void cil_post_fc_fill_data(struct fc_data *fc, char *path);
 int cil_post_filecon_compare(const void *a, const void *b);
 int cil_post_ibpkeycon_compare(const void *a, const void *b);
 int cil_post_portcon_compare(const void *a, const void *b);
+int cil_post_ibendportcon_compare(const void *a, const void *b);
 int cil_post_genfscon_compare(const void *a, const void *b);
 int cil_post_netifcon_compare(const void *a, const void *b);
 int cil_post_nodecon_compare(const void *a, const void *b);
diff --git a/libsepol/cil/src/cil_reset_ast.c b/libsepol/cil/src/cil_reset_ast.c
index fc23a2c8..73034a97 100644
--- a/libsepol/cil/src/cil_reset_ast.c
+++ b/libsepol/cil/src/cil_reset_ast.c
@@ -326,6 +326,13 @@ static void cil_reset_netifcon(struct cil_netifcon *netifcon)
 	}
 }
 
+static void cil_reset_ibendportcon(struct cil_ibendportcon *ibendportcon)
+{
+	if (!ibendportcon->context_str) {
+		cil_reset_context(ibendportcon->context);
+	}
+}
+
 static void cil_reset_pirqcon(struct cil_pirqcon *pirqcon)
 {
 	if (pirqcon->context_str == NULL) {
@@ -498,6 +505,9 @@ int __cil_reset_node(struct cil_tree_node *node,  __attribute__((unused)) uint32
 	case CIL_IBPKEYCON:
 		cil_reset_ibpkeycon(node->data);
 		break;
+	case CIL_IBENDPORTCON:
+		cil_reset_ibendportcon(node->data);
+		break;
 	case CIL_PORTCON:
 		cil_reset_portcon(node->data);
 		break;
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
index 9e3cb2b5..a6710683 100644
--- a/libsepol/cil/src/cil_resolve_ast.c
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -2086,6 +2086,31 @@ exit:
 	return rc;
 }
 
+int cil_resolve_ibendportcon(struct cil_tree_node *current, void *extra_args)
+{
+	struct cil_ibendportcon *ibendportcon = current->data;
+	struct cil_symtab_datum *con_datum = NULL;
+
+	int rc = SEPOL_ERR;
+
+	if (ibendportcon->context_str) {
+		rc = cil_resolve_name(current, ibendportcon->context_str, CIL_SYM_CONTEXTS, extra_args, &con_datum);
+		if (rc != SEPOL_OK)
+			goto exit;
+
+		ibendportcon->context = (struct cil_context *)con_datum;
+	} else {
+		rc = cil_resolve_context(current, ibendportcon->context, extra_args);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	return rc;
+}
+
 int cil_resolve_pirqcon(struct cil_tree_node *current, void *extra_args)
 {
 	struct cil_pirqcon *pirqcon = current->data;
@@ -3606,6 +3631,9 @@ int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
 		case CIL_NETIFCON:
 			rc = cil_resolve_netifcon(node, args);
 			break;
+		case CIL_IBENDPORTCON:
+			rc = cil_resolve_ibendportcon(node, args);
+			break;
 		case CIL_PIRQCON:
 			rc = cil_resolve_pirqcon(node, args);
 			break;
diff --git a/libsepol/cil/src/cil_resolve_ast.h b/libsepol/cil/src/cil_resolve_ast.h
index 0506a3de..82c8ea34 100644
--- a/libsepol/cil/src/cil_resolve_ast.h
+++ b/libsepol/cil/src/cil_resolve_ast.h
@@ -75,6 +75,7 @@ int cil_resolve_validatetrans(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_context(struct cil_tree_node *current, struct cil_context *context, void *extra_args);
 int cil_resolve_filecon(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_ibpkeycon(struct cil_tree_node *current, void *extra_args);
+int cil_resolve_ibendportcon(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_portcon(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_genfscon(struct cil_tree_node *current, void *extra_args);
 int cil_resolve_nodecon(struct cil_tree_node *current, void *extra_args);
diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c
index 89706d0f..d36401b4 100644
--- a/libsepol/cil/src/cil_tree.c
+++ b/libsepol/cil/src/cil_tree.c
@@ -1506,6 +1506,19 @@ void cil_tree_print_node(struct cil_tree_node *node)
 			cil_log(CIL_INFO, "\n");
 			return;
 		}
+		case CIL_IBENDPORTCON: {
+			struct cil_ibendportcon *ibendportcon = node->data;
+
+			cil_log(CIL_INFO, "IBENDPORTCON: %s %u ", ibendportcon->dev_name_str, ibendportcon->port);
+
+			if (ibendportcon->context)
+				cil_tree_print_context(ibendportcon->context);
+			else if (ibendportcon->context_str)
+				cil_log(CIL_INFO, " %s", ibendportcon->context_str);
+
+			cil_log(CIL_INFO, "\n");
+			return;
+		}
 		case CIL_PIRQCON: {
 			struct cil_pirqcon *pirqcon = node->data;
 
diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c
index 108da33d..1036d73c 100644
--- a/libsepol/cil/src/cil_verify.c
+++ b/libsepol/cil/src/cil_verify.c
@@ -1012,6 +1012,26 @@ exit:
 	return rc;
 }
 
+int __cil_verify_ibendportcon(struct cil_db *db, struct cil_tree_node *node)
+{
+	int rc = SEPOL_ERR;
+	struct cil_ibendportcon *ib_end_port = node->data;
+	struct cil_context *ctx = ib_end_port->context;
+
+	/* Verify only when anonymous */
+	if (!ctx->datum.name) {
+		rc = __cil_verify_context(db, ctx);
+		if (rc != SEPOL_OK)
+			goto exit;
+	}
+
+	return SEPOL_OK;
+
+exit:
+	cil_tree_log(node, CIL_ERR, "Invalid ibendportcon");
+	return rc;
+}
+
 int __cil_verify_genfscon(struct cil_db *db, struct cil_tree_node *node)
 {
 	int rc = SEPOL_ERR;
@@ -1475,6 +1495,9 @@ int __cil_verify_helper(struct cil_tree_node *node, uint32_t *finished, void *ex
 		case CIL_IBPKEYCON:
 			rc = __cil_verify_ibpkeycon(db, node);
 			break;
+		case CIL_IBENDPORTCON:
+			rc = __cil_verify_ibendportcon(db, node);
+			break;
 		case CIL_PORTCON:
 			rc = __cil_verify_portcon(db, node);
 			break;
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 7/9] semanage: Update semanage to allow runtime labeling of Infiniband Pkeys
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
                   ` (5 preceding siblings ...)
  2017-05-18 22:25 ` [PATCH v2 6/9] libsepol: Add IB end port handling to CIL Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-19 15:36   ` Stephen Smalley
  2017-05-18 22:25 ` [PATCH v2 8/9] semanage: Update semanage to allow runtime labeling of ibendports Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 9/9] semanage: Update man pages for infiniband Dan Jurgens
  8 siblings, 1 reply; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Update libsepol and libsemanage to work with pkey records. Add local
storage for new and modified pkey records in pkeys.local. Update semanage
to parse the pkey command options to add, modify, and delete pkeys.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>

---
v1:
Fixed semanage_pkey_exists -> semanage_ibpkey_exists in delete flow in
seobject.py

Stephen Smalley:
- Subnet prefix can't vary in size always 16 bytes, remove size field.
- Removed extraneous change in libsepol/VERSION
- Removed ifdef DARWIN s6_addr/32 blocks in favor of s6_addr.
- Got rid of magic constant for subnet prefix size.

Jason Zaman:
- Use SETools directly to query types in seobject.py.

v2:
Jason Zaman:
- Use set instead of sorted for valid_types.

Stephen Smalley:
- Fix semanage when ibpkey_type attribute isn't defined.
- Store subnet prefix in 8 bytes.
- Removed a missed #if DARWIN
- Use sizeof(struct in6_addr) vs a define.
---
 libsemanage/include/semanage/ibpkey_record.h  |  74 +++++
 libsemanage/include/semanage/ibpkeys_local.h  |  36 +++
 libsemanage/include/semanage/ibpkeys_policy.h |  28 ++
 libsemanage/include/semanage/semanage.h       |   3 +
 libsemanage/src/direct_api.c                  |  29 +-
 libsemanage/src/handle.h                      |  36 ++-
 libsemanage/src/ibpkey_internal.h             |  52 +++
 libsemanage/src/ibpkey_record.c               | 185 +++++++++++
 libsemanage/src/ibpkeys_file.c                | 181 +++++++++++
 libsemanage/src/ibpkeys_local.c               | 179 +++++++++++
 libsemanage/src/ibpkeys_policy.c              |  52 +++
 libsemanage/src/ibpkeys_policydb.c            |  62 ++++
 libsemanage/src/libsemanage.map               |   1 +
 libsemanage/src/policy_components.c           |   5 +-
 libsemanage/src/semanage_store.c              |   1 +
 libsemanage/src/semanage_store.h              |   1 +
 libsemanage/src/semanageswig.i                |   3 +
 libsemanage/src/semanageswig_python.i         |  43 +++
 libsemanage/utils/semanage_migrate_store      |   3 +-
 libsepol/include/sepol/ibpkey_record.h        |  77 +++++
 libsepol/include/sepol/ibpkeys.h              |  44 +++
 libsepol/include/sepol/sepol.h                |   2 +
 libsepol/src/ibpkey_internal.h                |  21 ++
 libsepol/src/ibpkey_record.c                  | 445 ++++++++++++++++++++++++++
 libsepol/src/ibpkeys.c                        | 269 ++++++++++++++++
 python/semanage/semanage                      |  60 +++-
 python/semanage/seobject.py                   | 255 +++++++++++++++
 27 files changed, 2131 insertions(+), 16 deletions(-)
 create mode 100644 libsemanage/include/semanage/ibpkey_record.h
 create mode 100644 libsemanage/include/semanage/ibpkeys_local.h
 create mode 100644 libsemanage/include/semanage/ibpkeys_policy.h
 create mode 100644 libsemanage/src/ibpkey_internal.h
 create mode 100644 libsemanage/src/ibpkey_record.c
 create mode 100644 libsemanage/src/ibpkeys_file.c
 create mode 100644 libsemanage/src/ibpkeys_local.c
 create mode 100644 libsemanage/src/ibpkeys_policy.c
 create mode 100644 libsemanage/src/ibpkeys_policydb.c
 create mode 100644 libsepol/include/sepol/ibpkey_record.h
 create mode 100644 libsepol/include/sepol/ibpkeys.h
 create mode 100644 libsepol/src/ibpkey_internal.h
 create mode 100644 libsepol/src/ibpkey_record.c
 create mode 100644 libsepol/src/ibpkeys.c

diff --git a/libsemanage/include/semanage/ibpkey_record.h b/libsemanage/include/semanage/ibpkey_record.h
new file mode 100644
index 00000000..59d5ff4a
--- /dev/null
+++ b/libsemanage/include/semanage/ibpkey_record.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc */
+
+#ifndef _SEMANAGE_IBPKEY_RECORD_H_
+#define _SEMANAGE_IBPKEY_RECORD_H_
+
+#include <semanage/context_record.h>
+#include <semanage/handle.h>
+#include <stddef.h>
+
+#ifndef _SEMANAGE_IBPKEY_DEFINED_
+struct semanage_ibpkey;
+struct semanage_ibpkey_key;
+typedef struct semanage_ibpkey semanage_ibpkey_t;
+typedef struct semanage_ibpkey_key semanage_ibpkey_key_t;
+#define _SEMANAGE_IBPKEY_DEFINED_
+#endif
+
+extern int semanage_ibpkey_compare(const semanage_ibpkey_t *ibpkey,
+				   const semanage_ibpkey_key_t *key);
+
+extern int semanage_ibpkey_compare2(const semanage_ibpkey_t *ibpkey,
+				    const semanage_ibpkey_t *ibpkey2);
+
+extern int semanage_ibpkey_key_create(semanage_handle_t *handle,
+				      const char *subnet_prefix,
+				      int low, int high,
+				      semanage_ibpkey_key_t **key_ptr);
+
+extern int semanage_ibpkey_key_extract(semanage_handle_t *handle,
+				       const semanage_ibpkey_t *ibpkey,
+				       semanage_ibpkey_key_t **key_ptr);
+
+extern void semanage_ibpkey_key_free(semanage_ibpkey_key_t *key);
+
+extern int semanage_ibpkey_get_subnet_prefix(semanage_handle_t *handle,
+					     const semanage_ibpkey_t *ibpkey,
+					     char **subnet_prefix_ptr);
+
+extern int semanage_ibpkey_get_subnet_prefix_bytes(semanage_handle_t *handle,
+						   const semanage_ibpkey_t *ibpkey,
+						   char **subnet_prefix);
+
+extern int semanage_ibpkey_set_subnet_prefix(semanage_handle_t *handle,
+					     semanage_ibpkey_t *ibpkey,
+					     const char *subnet_prefix);
+
+extern int semanage_ibpkey_set_subnet_prefix_bytes(semanage_handle_t *handle,
+						   semanage_ibpkey_t *ibpkey,
+						   const char *subnet_prefix);
+
+extern int semanage_ibpkey_get_low(const semanage_ibpkey_t *ibpkey);
+
+extern int semanage_ibpkey_get_high(const semanage_ibpkey_t *ibpkey);
+
+extern void semanage_ibpkey_set_pkey(semanage_ibpkey_t *ibpkey, int pkey_num);
+
+extern void semanage_ibpkey_set_range(semanage_ibpkey_t *ibpkey, int low, int high);
+
+extern semanage_context_t *semanage_ibpkey_get_con(const semanage_ibpkey_t *ibpkey);
+
+extern int semanage_ibpkey_set_con(semanage_handle_t *handle,
+				   semanage_ibpkey_t *ibpkey,
+				   semanage_context_t *con);
+
+extern int semanage_ibpkey_create(semanage_handle_t *handle,
+				  semanage_ibpkey_t **ibpkey_ptr);
+
+extern int semanage_ibpkey_clone(semanage_handle_t *handle,
+				 const semanage_ibpkey_t *ibpkey,
+				 semanage_ibpkey_t **ibpkey_ptr);
+
+extern void semanage_ibpkey_free(semanage_ibpkey_t *ibpkey);
+
+#endif
diff --git a/libsemanage/include/semanage/ibpkeys_local.h b/libsemanage/include/semanage/ibpkeys_local.h
new file mode 100644
index 00000000..079a642b
--- /dev/null
+++ b/libsemanage/include/semanage/ibpkeys_local.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc */
+
+#ifndef _SEMANAGE_IBPKEYS_LOCAL_H_
+#define _SEMANAGE_IBPKEYS_LOCAL_H_
+
+#include <semanage/ibpkey_record.h>
+#include <semanage/handle.h>
+
+extern int semanage_ibpkey_modify_local(semanage_handle_t *handle,
+					const semanage_ibpkey_key_t *key,
+					const semanage_ibpkey_t *data);
+
+extern int semanage_ibpkey_del_local(semanage_handle_t *handle,
+				     const semanage_ibpkey_key_t *key);
+
+extern int semanage_ibpkey_query_local(semanage_handle_t *handle,
+				       const semanage_ibpkey_key_t *key,
+				       semanage_ibpkey_t **response);
+
+extern int semanage_ibpkey_exists_local(semanage_handle_t *handle,
+					const semanage_ibpkey_key_t *key,
+					int *response);
+
+extern int semanage_ibpkey_count_local(semanage_handle_t *handle,
+				       unsigned int *response);
+
+extern int semanage_ibpkey_iterate_local(semanage_handle_t *handle,
+					 int (*handler)(const semanage_ibpkey_t *
+							record, void *varg),
+					 void *handler_arg);
+
+extern int semanage_ibpkey_list_local(semanage_handle_t *handle,
+				      semanage_ibpkey_t ***records,
+				      unsigned int *count);
+
+#endif
diff --git a/libsemanage/include/semanage/ibpkeys_policy.h b/libsemanage/include/semanage/ibpkeys_policy.h
new file mode 100644
index 00000000..c287ac02
--- /dev/null
+++ b/libsemanage/include/semanage/ibpkeys_policy.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2017 Mellanox Technolgies Inc. */
+
+#ifndef _SEMANAGE_IBPKEYS_POLICY_H_
+#define _SEMANAGE_IBPKEYS_POLICY_H_
+
+#include <semanage/handle.h>
+#include <semanage/ibpkey_record.h>
+
+extern int semanage_ibpkey_query(semanage_handle_t *handle,
+				 const semanage_ibpkey_key_t *key,
+				 semanage_ibpkey_t **response);
+
+extern int semanage_ibpkey_exists(semanage_handle_t *handle,
+				  const semanage_ibpkey_key_t *key, int *response);
+
+extern int semanage_ibpkey_count(semanage_handle_t *handle,
+				 unsigned int *response);
+
+extern int semanage_ibpkey_iterate(semanage_handle_t *handle,
+				   int (*handler)(const semanage_ibpkey_t *record,
+						  void *varg),
+				   void *handler_arg);
+
+extern int semanage_ibpkey_list(semanage_handle_t *handle,
+				semanage_ibpkey_t ***records,
+				unsigned int *count);
+
+#endif
diff --git a/libsemanage/include/semanage/semanage.h b/libsemanage/include/semanage/semanage.h
index f417ce4e..cebf3f44 100644
--- a/libsemanage/include/semanage/semanage.h
+++ b/libsemanage/include/semanage/semanage.h
@@ -33,6 +33,7 @@
 #include <semanage/context_record.h>
 #include <semanage/iface_record.h>
 #include <semanage/port_record.h>
+#include <semanage/ibpkey_record.h>
 #include <semanage/node_record.h>
 
 /* Dbase */
@@ -47,6 +48,8 @@
 #include <semanage/seusers_policy.h>
 #include <semanage/ports_local.h>
 #include <semanage/ports_policy.h>
+#include <semanage/ibpkeys_local.h>
+#include <semanage/ibpkeys_policy.h>
 #include <semanage/interfaces_local.h>
 #include <semanage/interfaces_policy.h>
 #include <semanage/nodes_local.h>
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index f4b04169..436e3340 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -40,6 +40,7 @@
 #include "user_internal.h"
 #include "seuser_internal.h"
 #include "port_internal.h"
+#include "ibpkey_internal.h"
 #include "iface_internal.h"
 #include "boolean_internal.h"
 #include "fcontext_internal.h"
@@ -224,6 +225,14 @@ int semanage_direct_connect(semanage_handle_t * sh)
 				 semanage_node_dbase_local(sh)) < 0)
 		goto err;
 
+	if (ibpkey_file_dbase_init(sh,
+				 semanage_path(SEMANAGE_ACTIVE,
+					       SEMANAGE_IBPKEYS_LOCAL),
+				 semanage_path(SEMANAGE_TMP,
+					       SEMANAGE_IBPKEYS_LOCAL),
+				 semanage_ibpkey_dbase_local(sh)) < 0)
+		goto err;
+
 	/* Object databases: local modifications + policy */
 	if (user_base_policydb_dbase_init(sh,
 					  semanage_user_base_dbase_policy(sh)) <
@@ -248,6 +257,9 @@ int semanage_direct_connect(semanage_handle_t * sh)
 	if (port_policydb_dbase_init(sh, semanage_port_dbase_policy(sh)) < 0)
 		goto err;
 
+	if (ibpkey_policydb_dbase_init(sh, semanage_ibpkey_dbase_policy(sh)) < 0)
+		goto err;
+
 	if (iface_policydb_dbase_init(sh, semanage_iface_dbase_policy(sh)) < 0)
 		goto err;
 
@@ -320,6 +332,7 @@ static int semanage_direct_disconnect(semanage_handle_t * sh)
 	user_extra_file_dbase_release(semanage_user_extra_dbase_local(sh));
 	user_join_dbase_release(semanage_user_dbase_local(sh));
 	port_file_dbase_release(semanage_port_dbase_local(sh));
+	ibpkey_file_dbase_release(semanage_ibpkey_dbase_local(sh));
 	iface_file_dbase_release(semanage_iface_dbase_local(sh));
 	bool_file_dbase_release(semanage_bool_dbase_local(sh));
 	fcontext_file_dbase_release(semanage_fcontext_dbase_local(sh));
@@ -331,6 +344,7 @@ static int semanage_direct_disconnect(semanage_handle_t * sh)
 	user_extra_file_dbase_release(semanage_user_extra_dbase_policy(sh));
 	user_join_dbase_release(semanage_user_dbase_policy(sh));
 	port_policydb_dbase_release(semanage_port_dbase_policy(sh));
+	ibpkey_policydb_dbase_release(semanage_ibpkey_dbase_policy(sh));
 	iface_policydb_dbase_release(semanage_iface_dbase_policy(sh));
 	bool_policydb_dbase_release(semanage_bool_dbase_policy(sh));
 	fcontext_file_dbase_release(semanage_fcontext_dbase_policy(sh));
@@ -1144,13 +1158,15 @@ static int semanage_direct_commit(semanage_handle_t * sh)
 
 	int do_rebuild, do_write_kernel, do_install;
 	int fcontexts_modified, ports_modified, seusers_modified,
-		disable_dontaudit, preserve_tunables;
+		disable_dontaudit, preserve_tunables, ibpkeys_modified;
 	dbase_config_t *users = semanage_user_dbase_local(sh);
 	dbase_config_t *users_base = semanage_user_base_dbase_local(sh);
 	dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh);
 	dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh);
 	dbase_config_t *ports = semanage_port_dbase_local(sh);
 	dbase_config_t *pports = semanage_port_dbase_policy(sh);
+	dbase_config_t *ibpkeys = semanage_ibpkey_dbase_local(sh);
+	dbase_config_t *pibpkeys = semanage_ibpkey_dbase_policy(sh);
 	dbase_config_t *bools = semanage_bool_dbase_local(sh);
 	dbase_config_t *pbools = semanage_bool_dbase_policy(sh);
 	dbase_config_t *ifaces = semanage_iface_dbase_local(sh);
@@ -1164,6 +1180,7 @@ static int semanage_direct_commit(semanage_handle_t * sh)
 
 	/* Modified flags that we need to use more than once. */
 	ports_modified = ports->dtable->is_modified(ports->dbase);
+	ibpkeys_modified = ibpkeys->dtable->is_modified(ibpkeys->dbase);
 	seusers_modified = seusers->dtable->is_modified(seusers->dbase);
 	fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
 
@@ -1285,7 +1302,7 @@ rebuild:
 	 * that live under /etc/selinux (kernel policy, seusers, file contexts)
 	 * will be modified.
 	 */
-	do_write_kernel = do_rebuild | ports_modified |
+	do_write_kernel = do_rebuild | ports_modified | ibpkeys_modified |
 		bools->dtable->is_modified(bools->dbase) |
 		ifaces->dtable->is_modified(ifaces->dbase) |
 		nodes->dtable->is_modified(nodes->dbase) |
@@ -1431,6 +1448,7 @@ rebuild:
 	/* Attach our databases to the policydb we just created or loaded. */
 	dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
+	dbase_policydb_attach((dbase_policydb_t *) pibpkeys->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
@@ -1479,6 +1497,12 @@ rebuild:
 			goto cleanup;
 	}
 
+	/* Validate local ibpkeys for overlap */
+	if (do_rebuild || ibpkeys_modified) {
+		retval = semanage_ibpkey_validate_local(sh);
+		if (retval < 0)
+			goto cleanup;
+	}
 	/* ================== Write non-policydb components ========= */
 
 	/* Commit changes to components */
@@ -1558,6 +1582,7 @@ cleanup:
 	/* Detach from policydb, so it can be freed */
 	dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
+	dbase_policydb_detach((dbase_policydb_t *) pibpkeys->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
diff --git a/libsemanage/src/handle.h b/libsemanage/src/handle.h
index 64175c4e..306727a2 100644
--- a/libsemanage/src/handle.h
+++ b/libsemanage/src/handle.h
@@ -79,7 +79,7 @@ struct semanage_handle {
 	struct semanage_policy_table *funcs;
 
 	/* Object databases */
-#define DBASE_COUNT      19
+#define DBASE_COUNT      21
 
 /* Local modifications */
 #define DBASE_LOCAL_USERS_BASE  0
@@ -91,20 +91,22 @@ struct semanage_handle {
 #define DBASE_LOCAL_FCONTEXTS	6
 #define DBASE_LOCAL_SEUSERS     7
 #define DBASE_LOCAL_NODES       8
+#define DBASE_LOCAL_IBPKEYS     9
 
 /* Policy + Local modifications */
-#define DBASE_POLICY_USERS_BASE  9
-#define DBASE_POLICY_USERS_EXTRA 10
-#define DBASE_POLICY_USERS       11
-#define DBASE_POLICY_PORTS       12
-#define DBASE_POLICY_INTERFACES  13
-#define DBASE_POLICY_BOOLEANS    14
-#define DBASE_POLICY_FCONTEXTS   15
-#define DBASE_POLICY_SEUSERS     16
-#define DBASE_POLICY_NODES       17
+#define DBASE_POLICY_USERS_BASE  10
+#define DBASE_POLICY_USERS_EXTRA 11
+#define DBASE_POLICY_USERS       12
+#define DBASE_POLICY_PORTS       13
+#define DBASE_POLICY_INTERFACES  14
+#define DBASE_POLICY_BOOLEANS    15
+#define DBASE_POLICY_FCONTEXTS   16
+#define DBASE_POLICY_SEUSERS     17
+#define DBASE_POLICY_NODES       18
+#define DBASE_POLICY_IBPKEYS     19
 
 /* Active kernel policy */
-#define DBASE_ACTIVE_BOOLEANS    18
+#define DBASE_ACTIVE_BOOLEANS    20
 	dbase_config_t dbase[DBASE_COUNT];
 };
 
@@ -134,6 +136,12 @@ static inline
 }
 
 static inline
+    dbase_config_t * semanage_ibpkey_dbase_local(semanage_handle_t * handle)
+{
+	return &handle->dbase[DBASE_LOCAL_IBPKEYS];
+}
+
+static inline
     dbase_config_t * semanage_iface_dbase_local(semanage_handle_t * handle)
 {
 	return &handle->dbase[DBASE_LOCAL_INTERFACES];
@@ -190,6 +198,12 @@ static inline
 }
 
 static inline
+    dbase_config_t * semanage_ibpkey_dbase_policy(semanage_handle_t * handle)
+{
+	return &handle->dbase[DBASE_POLICY_IBPKEYS];
+}
+
+static inline
     dbase_config_t * semanage_iface_dbase_policy(semanage_handle_t * handle)
 {
 	return &handle->dbase[DBASE_POLICY_INTERFACES];
diff --git a/libsemanage/src/ibpkey_internal.h b/libsemanage/src/ibpkey_internal.h
new file mode 100644
index 00000000..9465bb8d
--- /dev/null
+++ b/libsemanage/src/ibpkey_internal.h
@@ -0,0 +1,52 @@
+#ifndef _SEMANAGE_IBPKEY_INTERNAL_H_
+#define _SEMANAGE_IBPKEY_INTERNAL_H_
+
+#include <semanage/ibpkey_record.h>
+#include <semanage/ibpkeys_local.h>
+#include <semanage/ibpkeys_policy.h>
+#include "database.h"
+#include "handle.h"
+#include "dso.h"
+
+hidden_proto(semanage_ibpkey_create)
+hidden_proto(semanage_ibpkey_compare)
+hidden_proto(semanage_ibpkey_compare2)
+hidden_proto(semanage_ibpkey_clone)
+hidden_proto(semanage_ibpkey_free)
+hidden_proto(semanage_ibpkey_key_extract)
+hidden_proto(semanage_ibpkey_key_free)
+hidden_proto(semanage_ibpkey_get_high)
+hidden_proto(semanage_ibpkey_get_low)
+hidden_proto(semanage_ibpkey_set_pkey)
+hidden_proto(semanage_ibpkey_set_range)
+hidden_proto(semanage_ibpkey_get_con)
+hidden_proto(semanage_ibpkey_set_con)
+hidden_proto(semanage_ibpkey_list_local)
+hidden_proto(semanage_ibpkey_get_subnet_prefix)
+hidden_proto(semanage_ibpkey_get_subnet_prefix_bytes)
+hidden_proto(semanage_ibpkey_set_subnet_prefix)
+hidden_proto(semanage_ibpkey_set_subnet_prefix_bytes)
+
+/* PKEY RECORD: method table */
+extern record_table_t SEMANAGE_IBPKEY_RTABLE;
+
+extern int ibpkey_file_dbase_init(semanage_handle_t *handle,
+				  const char *path_ro,
+				  const char *path_rw,
+				  dbase_config_t *dconfig);
+
+extern void ibpkey_file_dbase_release(dbase_config_t *dconfig);
+
+extern int ibpkey_policydb_dbase_init(semanage_handle_t *handle,
+				      dbase_config_t *dconfig);
+
+extern void ibpkey_policydb_dbase_release(dbase_config_t *dconfig);
+
+extern int hidden semanage_ibpkey_validate_local(semanage_handle_t *handle);
+
+/* ==== Internal (to ibpkeys) API === */
+
+hidden int semanage_ibpkey_compare2_qsort(const semanage_ibpkey_t **ibpkey,
+					  const semanage_ibpkey_t **ibpkey2);
+
+#endif
diff --git a/libsemanage/src/ibpkey_record.c b/libsemanage/src/ibpkey_record.c
new file mode 100644
index 00000000..707eebd1
--- /dev/null
+++ b/libsemanage/src/ibpkey_record.c
@@ -0,0 +1,185 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc. */
+
+/* Object: semanage_ibpkey_t (Infiniband Pkey)
+ * Object: semanage_ibpkey_key_t (Infiniband Pkey Key)
+ * Implements: record_t (Database Record)
+ * Implements: record_key_t (Database Record Key)
+ */
+
+#include <sepol/context_record.h>
+#include <sepol/ibpkey_record.h>
+
+typedef sepol_context_t semanage_context_t;
+typedef sepol_ibpkey_t semanage_ibpkey_t;
+typedef sepol_ibpkey_key_t semanage_ibpkey_key_t;
+#define _SEMANAGE_IBPKEY_DEFINED_
+#define _SEMANAGE_CONTEXT_DEFINED_
+
+typedef semanage_ibpkey_t record_t;
+typedef semanage_ibpkey_key_t record_key_t;
+#define DBASE_RECORD_DEFINED
+
+#include "ibpkey_internal.h"
+#include "handle.h"
+#include "database.h"
+
+int semanage_ibpkey_compare(const semanage_ibpkey_t *ibpkey,
+			    const semanage_ibpkey_key_t *key)
+{
+	return sepol_ibpkey_compare(ibpkey, key);
+}
+
+hidden_def(semanage_ibpkey_compare)
+
+int semanage_ibpkey_compare2(const semanage_ibpkey_t *ibpkey,
+			     const semanage_ibpkey_t *ibpkey2)
+{
+	return sepol_ibpkey_compare2(ibpkey, ibpkey2);
+}
+
+hidden_def(semanage_ibpkey_compare2)
+
+hidden int semanage_ibpkey_compare2_qsort(const semanage_ibpkey_t **ibpkey,
+					  const semanage_ibpkey_t **ibpkey2)
+{
+	return sepol_ibpkey_compare2(*ibpkey, *ibpkey2);
+}
+
+int semanage_ibpkey_key_create(semanage_handle_t *handle,
+			       const char *subnet_prefix,
+			       int low, int high,
+			       semanage_ibpkey_key_t **key_ptr)
+{
+	return sepol_ibpkey_key_create(handle->sepolh, subnet_prefix, low, high, key_ptr);
+}
+
+int semanage_ibpkey_key_extract(semanage_handle_t *handle,
+				const semanage_ibpkey_t *ibpkey,
+				semanage_ibpkey_key_t **key_ptr)
+{
+	return sepol_ibpkey_key_extract(handle->sepolh, ibpkey, key_ptr);
+}
+
+hidden_def(semanage_ibpkey_key_extract)
+
+void semanage_ibpkey_key_free(semanage_ibpkey_key_t *key)
+{
+	sepol_ibpkey_key_free(key);
+}
+
+hidden_def(semanage_ibpkey_key_free)
+
+int semanage_ibpkey_get_subnet_prefix(semanage_handle_t *handle,
+				      const semanage_ibpkey_t *ibpkey,
+				      char **subnet_prefix_ptr)
+{
+	return sepol_ibpkey_get_subnet_prefix(handle->sepolh, ibpkey, subnet_prefix_ptr);
+}
+
+hidden_def(semanage_ibpkey_get_subnet_prefix)
+
+int semanage_ibpkey_get_subnet_prefix_bytes(semanage_handle_t *handle,
+					    const semanage_ibpkey_t *ibpkey,
+					    char **subnet_prefix)
+{
+	return sepol_ibpkey_get_subnet_prefix_bytes(handle->sepolh, ibpkey, subnet_prefix);
+}
+
+hidden_def(semanage_ibpkey_get_subnet_prefix_bytes)
+
+int semanage_ibpkey_set_subnet_prefix(semanage_handle_t *handle,
+				      semanage_ibpkey_t *ibpkey,
+				      const char *subnet_prefix)
+{
+	return sepol_ibpkey_set_subnet_prefix(handle->sepolh, ibpkey, subnet_prefix);
+}
+
+hidden_def(semanage_ibpkey_set_subnet_prefix)
+
+int semanage_ibpkey_set_subnet_prefix_bytes(semanage_handle_t *handle,
+					    semanage_ibpkey_t *ibpkey,
+					    const char *subnet_prefix)
+{
+	return sepol_ibpkey_set_subnet_prefix_bytes(handle->sepolh, ibpkey, subnet_prefix);
+}
+
+hidden_def(semanage_ibpkey_set_subnet_prefix_bytes)
+
+int semanage_ibpkey_get_low(const semanage_ibpkey_t *ibpkey)
+{
+	return sepol_ibpkey_get_low(ibpkey);
+}
+
+hidden_def(semanage_ibpkey_get_low)
+
+int semanage_ibpkey_get_high(const semanage_ibpkey_t *ibpkey)
+{
+	return sepol_ibpkey_get_high(ibpkey);
+}
+
+hidden_def(semanage_ibpkey_get_high)
+
+void semanage_ibpkey_set_pkey(semanage_ibpkey_t *ibpkey, int ibpkey_num)
+{
+	sepol_ibpkey_set_pkey(ibpkey, ibpkey_num);
+}
+
+hidden_def(semanage_ibpkey_set_pkey)
+
+void semanage_ibpkey_set_range(semanage_ibpkey_t *ibpkey, int low, int high)
+{
+	sepol_ibpkey_set_range(ibpkey, low, high);
+}
+
+hidden_def(semanage_ibpkey_set_range)
+
+semanage_context_t *semanage_ibpkey_get_con(const semanage_ibpkey_t *ibpkey)
+{
+	return sepol_ibpkey_get_con(ibpkey);
+}
+
+hidden_def(semanage_ibpkey_get_con)
+
+int semanage_ibpkey_set_con(semanage_handle_t *handle,
+			    semanage_ibpkey_t *ibpkey, semanage_context_t *con)
+{
+	return sepol_ibpkey_set_con(handle->sepolh, ibpkey, con);
+}
+
+hidden_def(semanage_ibpkey_set_con)
+
+int semanage_ibpkey_create(semanage_handle_t *handle,
+			   semanage_ibpkey_t **ibpkey_ptr)
+{
+	return sepol_ibpkey_create(handle->sepolh, ibpkey_ptr);
+}
+
+hidden_def(semanage_ibpkey_create)
+
+int semanage_ibpkey_clone(semanage_handle_t *handle,
+			  const semanage_ibpkey_t *ibpkey,
+			  semanage_ibpkey_t **ibpkey_ptr)
+{
+	return sepol_ibpkey_clone(handle->sepolh, ibpkey, ibpkey_ptr);
+}
+
+hidden_def(semanage_ibpkey_clone)
+
+void semanage_ibpkey_free(semanage_ibpkey_t *ibpkey)
+{
+	sepol_ibpkey_free(ibpkey);
+}
+
+hidden_def(semanage_ibpkey_free)
+
+/* key base functions */
+record_table_t SEMANAGE_IBPKEY_RTABLE = {
+	.create = semanage_ibpkey_create,
+	.key_extract = semanage_ibpkey_key_extract,
+	.key_free = semanage_ibpkey_key_free,
+	.clone = semanage_ibpkey_clone,
+	.compare = semanage_ibpkey_compare,
+	.compare2 = semanage_ibpkey_compare2,
+	.compare2_qsort = semanage_ibpkey_compare2_qsort,
+	.free = semanage_ibpkey_free,
+};
diff --git a/libsemanage/src/ibpkeys_file.c b/libsemanage/src/ibpkeys_file.c
new file mode 100644
index 00000000..ceaea7ad
--- /dev/null
+++ b/libsemanage/src/ibpkeys_file.c
@@ -0,0 +1,181 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc. */
+
+struct semanage_ibpkey;
+struct semanage_ibpkey_key;
+typedef struct semanage_ibpkey record_t;
+typedef struct semanage_ibpkey_key record_key_t;
+#define DBASE_RECORD_DEFINED
+
+struct dbase_file;
+typedef struct dbase_file dbase_t;
+#define DBASE_DEFINED
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <semanage/handle.h>
+#include "ibpkey_internal.h"
+#include "context_internal.h"
+#include "database_file.h"
+#include "parse_utils.h"
+#include "debug.h"
+
+static int ibpkey_print(semanage_handle_t *handle,
+			semanage_ibpkey_t *ibpkey, FILE *str)
+{
+	char *con_str = NULL;
+	char *subnet_prefix_str = NULL;
+
+	int low = semanage_ibpkey_get_low(ibpkey);
+	int high = semanage_ibpkey_get_high(ibpkey);
+
+	if (semanage_ibpkey_get_subnet_prefix(handle, ibpkey, &subnet_prefix_str) != 0)
+		goto err;
+
+	semanage_context_t *con = semanage_ibpkey_get_con(ibpkey);
+
+	if (fprintf(str, "ibpkeycon %s ", subnet_prefix_str) < 0)
+		goto err;
+
+	if (low == high) {
+		if (fprintf(str, "%d ", low) < 0)
+			goto err;
+	} else {
+		if (fprintf(str, "%d - %d ", low, high) < 0)
+			goto err;
+	}
+
+	if (semanage_context_to_string(handle, con, &con_str) < 0)
+		goto err;
+	if (fprintf(str, "%s\n", con_str) < 0)
+		goto err;
+
+	free(subnet_prefix_str);
+	free(con_str);
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not print ibpkey range (%s) %u - %u to stream",
+	    subnet_prefix_str, low, high);
+	free(subnet_prefix_str);
+	free(con_str);
+	return STATUS_ERR;
+}
+
+static int ibpkey_parse(semanage_handle_t *handle,
+			parse_info_t *info, semanage_ibpkey_t *ibpkey)
+{
+	int low, high;
+	char *str = NULL;
+	semanage_context_t *con = NULL;
+
+	if (parse_skip_space(handle, info) < 0)
+		goto err;
+	if (!info->ptr)
+		goto last;
+
+	/* Header */
+	if (parse_assert_str(handle, info, "ibpkeycon") < 0)
+		goto err;
+	if (parse_assert_space(handle, info) < 0)
+		goto err;
+
+	/* Subnet Prefix */
+	if (parse_fetch_string(handle, info, &str, ' ') < 0)
+		goto err;
+	if (semanage_ibpkey_set_subnet_prefix(handle, ibpkey, str) < 0)
+		goto err;
+	free(str);
+	str = NULL;
+
+	/* Range/Pkey */
+	if (parse_assert_space(handle, info) < 0)
+		goto err;
+	if (parse_fetch_int(handle, info, &low, '-') < 0)
+		goto err;
+
+	/* If range (-) does not follow immediately, require a space
+	 * In other words, the space here is optional, but only
+	 * in the ranged case, not in the single ibpkey case,
+	 * so do a custom test
+	 */
+	if (*info->ptr && *info->ptr != '-') {
+		if (parse_assert_space(handle, info) < 0)
+			goto err;
+	}
+
+	if (parse_optional_ch(info, '-') != STATUS_NODATA) {
+		if (parse_skip_space(handle, info) < 0)
+			goto err;
+		if (parse_fetch_int(handle, info, &high, ' ') < 0)
+			goto err;
+		if (parse_assert_space(handle, info) < 0)
+			goto err;
+		semanage_ibpkey_set_range(ibpkey, low, high);
+	} else {
+		semanage_ibpkey_set_pkey(ibpkey, low);
+	}
+	/* Pkey context */
+	if (parse_fetch_string(handle, info, &str, ' ') < 0)
+		goto err;
+	if (semanage_context_from_string(handle, str, &con) < 0) {
+		ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
+		    str, info->filename, info->lineno, info->orig_line);
+		goto err;
+	}
+	if (!con) {
+		ERR(handle, "<<none>> context is not valid for ibpkeys (%s: %u):\n%s",
+		    info->filename,
+		    info->lineno, info->orig_line);
+		goto err;
+	}
+	free(str);
+	str = NULL;
+
+	if (semanage_ibpkey_set_con(handle, ibpkey, con) < 0)
+		goto err;
+
+	if (parse_assert_space(handle, info) < 0)
+		goto err;
+
+	semanage_context_free(con);
+	return STATUS_SUCCESS;
+
+last:
+	parse_dispose_line(info);
+	return STATUS_NODATA;
+
+err:
+	ERR(handle, "could not parse ibpkey record");
+	free(str);
+	semanage_context_free(con);
+	parse_dispose_line(info);
+	return STATUS_ERR;
+}
+
+/* IBPKEY RECORD: FILE extension: method table */
+record_file_table_t SEMANAGE_IBPKEY_FILE_RTABLE = {
+	.parse = ibpkey_parse,
+	.print = ibpkey_print,
+};
+
+int ibpkey_file_dbase_init(semanage_handle_t *handle,
+			   const char *path_ro,
+			   const char *path_rw,
+			   dbase_config_t *dconfig)
+{
+	if (dbase_file_init(handle,
+			    path_ro,
+			    path_rw,
+			    &SEMANAGE_IBPKEY_RTABLE,
+			    &SEMANAGE_IBPKEY_FILE_RTABLE, &dconfig->dbase) < 0)
+		return STATUS_ERR;
+
+	dconfig->dtable = &SEMANAGE_FILE_DTABLE;
+	return STATUS_SUCCESS;
+}
+
+void ibpkey_file_dbase_release(dbase_config_t *dconfig)
+{
+	dbase_file_release(dconfig->dbase);
+}
diff --git a/libsemanage/src/ibpkeys_local.c b/libsemanage/src/ibpkeys_local.c
new file mode 100644
index 00000000..82253079
--- /dev/null
+++ b/libsemanage/src/ibpkeys_local.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc. */
+
+struct semanage_ibpkey;
+struct semanage_ibpkey_key;
+typedef struct semanage_ibpkey_key record_key_t;
+typedef struct semanage_ibpkey record_t;
+#define DBASE_RECORD_DEFINED
+
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include "ibpkey_internal.h"
+#include "debug.h"
+#include "handle.h"
+#include "database.h"
+
+int semanage_ibpkey_modify_local(semanage_handle_t *handle,
+				 const semanage_ibpkey_key_t *key,
+				 const semanage_ibpkey_t *data)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle);
+
+	return dbase_modify(handle, dconfig, key, data);
+}
+
+int semanage_ibpkey_del_local(semanage_handle_t *handle,
+			      const semanage_ibpkey_key_t *key)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle);
+
+	return dbase_del(handle, dconfig, key);
+}
+
+int semanage_ibpkey_query_local(semanage_handle_t *handle,
+				const semanage_ibpkey_key_t *key,
+				semanage_ibpkey_t **response)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle);
+
+	return dbase_query(handle, dconfig, key, response);
+}
+
+int semanage_ibpkey_exists_local(semanage_handle_t *handle,
+				 const semanage_ibpkey_key_t *key,
+				 int *response)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle);
+
+	return dbase_exists(handle, dconfig, key, response);
+}
+
+int semanage_ibpkey_count_local(semanage_handle_t *handle,
+				unsigned int *response)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle);
+
+	return dbase_count(handle, dconfig, response);
+}
+
+int semanage_ibpkey_iterate_local(semanage_handle_t *handle,
+				  int (*handler)(const semanage_ibpkey_t *record,
+						 void *varg), void *handler_arg)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle);
+
+	return dbase_iterate(handle, dconfig, handler, handler_arg);
+}
+
+int semanage_ibpkey_list_local(semanage_handle_t *handle,
+			       semanage_ibpkey_t ***records, unsigned int *count)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_local(handle);
+
+	return dbase_list(handle, dconfig, records, count);
+}
+
+hidden_def(semanage_ibpkey_list_local)
+
+int hidden semanage_ibpkey_validate_local(semanage_handle_t *handle)
+{
+	semanage_ibpkey_t **ibpkeys = NULL;
+	unsigned int nibpkeys = 0;
+	unsigned int i = 0, j = 0;
+	char *subnet_prefix;
+	char *subnet_prefix2;
+	char *subnet_prefix_str;
+	char *subnet_prefix_str2;
+	int low, high;
+	int low2, high2;
+
+	/* List and sort the ibpkeys */
+	if (semanage_ibpkey_list_local(handle, &ibpkeys, &nibpkeys) < 0)
+		goto err;
+
+	qsort(ibpkeys, nibpkeys, sizeof(semanage_ibpkey_t *),
+	      (int (*)(const void *, const void *))
+	      &semanage_ibpkey_compare2_qsort);
+
+	/* Test each ibpkey for overlap */
+	while (i < nibpkeys) {
+		int stop = 0;
+
+		if (STATUS_SUCCESS !=
+				semanage_ibpkey_get_subnet_prefix_bytes(handle,
+								      ibpkeys[i],
+								      &subnet_prefix)) {
+			ERR(handle, "Couldn't get subnet prefix");
+			goto err;
+		}
+		if (STATUS_SUCCESS != semanage_ibpkey_get_subnet_prefix(handle,
+									ibpkeys[i],
+									&subnet_prefix_str)) {
+			ERR(handle, "Couldn't get subnet prefix string");
+			goto err;
+		}
+
+		low = semanage_ibpkey_get_low(ibpkeys[i]);
+		high = semanage_ibpkey_get_high(ibpkeys[i]);
+
+		/* Find the first ibpkey with matching
+		 * subnet_prefix to compare against
+		 */
+		do {
+			if (j == nibpkeys - 1)
+				goto next;
+			j++;
+			if (STATUS_SUCCESS !=
+				semanage_ibpkey_get_subnet_prefix_bytes(handle,
+									ibpkeys[j],
+									&subnet_prefix2)) {
+				ERR(handle, "Couldn't get subnet prefix");
+				goto err;
+			}
+			if (STATUS_SUCCESS !=
+				semanage_ibpkey_get_subnet_prefix(handle,
+								ibpkeys[j],
+								&subnet_prefix_str2)) {
+				ERR(handle, "Couldn't get subnet prefix string");
+				goto err;
+			}
+			low2 = semanage_ibpkey_get_low(ibpkeys[j]);
+			high2 = semanage_ibpkey_get_high(ibpkeys[j]);
+
+			stop = !memcmp(subnet_prefix, subnet_prefix2, sizeof(struct in6_addr));
+		} while (!stop);
+
+		/* Overlap detected */
+		if (low2 <= high) {
+			ERR(handle, "ibpkey overlap between ranges "
+			    "(%s) %u - %u <--> (%s) %u - %u.",
+			    subnet_prefix_str, low, high,
+			    subnet_prefix_str2, low2, high2);
+			goto invalid;
+		}
+
+		/* If closest ibpkey of matching subnet prefix doesn't overlap
+		 * with test ibpkey, neither do the rest of them, because that's
+		 * how the sort function works on ibpkeys - lower bound
+		 * ibpkeys come first
+		 */
+next:
+		i++;
+		j = i;
+	}
+
+	for (i = 0; i < nibpkeys; i++)
+		semanage_ibpkey_free(ibpkeys[i]);
+	free(ibpkeys);
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not complete ibpkeys validity check");
+
+invalid:
+	for (i = 0; i < nibpkeys; i++)
+		semanage_ibpkey_free(ibpkeys[i]);
+	free(ibpkeys);
+	return STATUS_ERR;
+}
diff --git a/libsemanage/src/ibpkeys_policy.c b/libsemanage/src/ibpkeys_policy.c
new file mode 100644
index 00000000..09562307
--- /dev/null
+++ b/libsemanage/src/ibpkeys_policy.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc. */
+
+struct semanage_ibpkey;
+struct semanage_ibpkey_key;
+typedef struct semanage_ibpkey_key record_key_t;
+typedef struct semanage_ibpkey record_t;
+#define DBASE_RECORD_DEFINED
+
+#include "ibpkey_internal.h"
+#include "handle.h"
+#include "database.h"
+
+int semanage_ibpkey_query(semanage_handle_t *handle,
+			  const semanage_ibpkey_key_t *key,
+			  semanage_ibpkey_t **response)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle);
+
+	return dbase_query(handle, dconfig, key, response);
+}
+
+int semanage_ibpkey_exists(semanage_handle_t *handle,
+			   const semanage_ibpkey_key_t *key, int *response)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle);
+
+	return dbase_exists(handle, dconfig, key, response);
+}
+
+int semanage_ibpkey_count(semanage_handle_t *handle, unsigned int *response)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle);
+
+	return dbase_count(handle, dconfig, response);
+}
+
+int semanage_ibpkey_iterate(semanage_handle_t *handle,
+			    int (*handler)(const semanage_ibpkey_t *record,
+					   void *varg), void *handler_arg)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle);
+
+	return dbase_iterate(handle, dconfig, handler, handler_arg);
+}
+
+int semanage_ibpkey_list(semanage_handle_t *handle,
+			 semanage_ibpkey_t ***records, unsigned int *count)
+{
+	dbase_config_t *dconfig = semanage_ibpkey_dbase_policy(handle);
+
+	return dbase_list(handle, dconfig, records, count);
+}
diff --git a/libsemanage/src/ibpkeys_policydb.c b/libsemanage/src/ibpkeys_policydb.c
new file mode 100644
index 00000000..8d73cf6f
--- /dev/null
+++ b/libsemanage/src/ibpkeys_policydb.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 Mellanox Technologies Inc
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ */
+
+struct semanage_ibpkey;
+struct semanage_ibpkey_key;
+typedef struct semanage_ibpkey record_t;
+typedef struct semanage_ibpkey_key record_key_t;
+#define DBASE_RECORD_DEFINED
+
+struct dbase_policydb;
+typedef struct dbase_policydb dbase_t;
+#define DBASE_DEFINED
+
+#include <sepol/ibpkeys.h>
+#include <semanage/handle.h>
+#include "ibpkey_internal.h"
+#include "debug.h"
+#include "database_policydb.h"
+#include "semanage_store.h"
+
+/* PKEY RECORD (SEPOL): POLICYDB extension : method table */
+record_policydb_table_t SEMANAGE_IBPKEY_POLICYDB_RTABLE = {
+	.add = NULL,
+	.modify = (record_policydb_table_modify_t)sepol_ibpkey_modify,
+	.set = NULL,
+	.query = (record_policydb_table_query_t)sepol_ibpkey_query,
+	.count = (record_policydb_table_count_t)sepol_ibpkey_count,
+	.exists = (record_policydb_table_exists_t)sepol_ibpkey_exists,
+	.iterate = (record_policydb_table_iterate_t)sepol_ibpkey_iterate,
+};
+
+int ibpkey_policydb_dbase_init(semanage_handle_t *handle,
+			       dbase_config_t *dconfig)
+{
+	if (dbase_policydb_init(handle,
+				semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL),
+				semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
+				&SEMANAGE_IBPKEY_RTABLE,
+				&SEMANAGE_IBPKEY_POLICYDB_RTABLE,
+				&dconfig->dbase) < 0)
+		return STATUS_ERR;
+
+	dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE;
+
+	return STATUS_SUCCESS;
+}
+
+void ibpkey_policydb_dbase_release(dbase_config_t *dconfig)
+{
+	dbase_policydb_release(dconfig->dbase);
+}
diff --git a/libsemanage/src/libsemanage.map b/libsemanage/src/libsemanage.map
index 9f8a754d..041b1ce1 100644
--- a/libsemanage/src/libsemanage.map
+++ b/libsemanage/src/libsemanage.map
@@ -18,6 +18,7 @@ LIBSEMANAGE_1.0 {
 	  semanage_root;
 	  semanage_user_*; semanage_bool_*; semanage_seuser_*;
 	  semanage_iface_*; semanage_port_*; semanage_context_*;
+	  semanage_ibpkey_*;
 	  semanage_node_*;
 	  semanage_fcontext_*; semanage_access_check; semanage_set_create_store;
 	  semanage_is_connected; semanage_get_disable_dontaudit; semanage_set_disable_dontaudit;
diff --git a/libsemanage/src/policy_components.c b/libsemanage/src/policy_components.c
index d31bd489..136c5a76 100644
--- a/libsemanage/src/policy_components.c
+++ b/libsemanage/src/policy_components.c
@@ -137,12 +137,14 @@ int semanage_base_merge_components(semanage_handle_t * handle)
 
 		{semanage_node_dbase_local(handle),
 		 semanage_node_dbase_policy(handle), MODE_MODIFY | MODE_SORT},
+
+		{semanage_ibpkey_dbase_local(handle),
+		 semanage_ibpkey_dbase_policy(handle), MODE_MODIFY},
 	};
 	const unsigned int CCOUNT = sizeof(components) / sizeof(components[0]);
 
 	/* Merge components into policy (and validate) */
 	for (i = 0; i < CCOUNT; i++) {
-
 		record_t **records = NULL;
 		unsigned int nrecords = 0;
 
@@ -218,6 +220,7 @@ int semanage_commit_components(semanage_handle_t * handle)
 		semanage_seuser_dbase_policy(handle),
 		semanage_bool_dbase_active(handle),
 		semanage_node_dbase_local(handle),
+		semanage_ibpkey_dbase_local(handle),
 	};
 	const int CCOUNT = sizeof(components) / sizeof(components[0]);
 
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index 6b750027..f61f3b2e 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -99,6 +99,7 @@ static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
 	"/homedir_template",
 	"/file_contexts.template",
 	"/commit_num",
+	"/pkeys.local",
 	"/ports.local",
 	"/interfaces.local",
 	"/nodes.local",
diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h
index 0b96fbe9..c7bcf443 100644
--- a/libsemanage/src/semanage_store.h
+++ b/libsemanage/src/semanage_store.h
@@ -44,6 +44,7 @@ enum semanage_sandbox_defs {
 	SEMANAGE_HOMEDIR_TMPL,
 	SEMANAGE_FC_TMPL,
 	SEMANAGE_COMMIT_NUM_FILE,
+	SEMANAGE_IBPKEYS_LOCAL,
 	SEMANAGE_PORTS_LOCAL,
 	SEMANAGE_INTERFACES_LOCAL,
 	SEMANAGE_NODES_LOCAL,
diff --git a/libsemanage/src/semanageswig.i b/libsemanage/src/semanageswig.i
index 583b7d86..d3ca7959 100644
--- a/libsemanage/src/semanageswig.i
+++ b/libsemanage/src/semanageswig.i
@@ -39,6 +39,9 @@
 %include "../include/semanage/port_record.h"
 %include "../include/semanage/ports_local.h"
 %include "../include/semanage/ports_policy.h"
+%include "../include/semanage/ibpkey_record.h"
+%include "../include/semanage/ibpkeys_local.h"
+%include "../include/semanage/ibpkeys_policy.h"
 %include "../include/semanage/fcontext_record.h"
 %include "../include/semanage/fcontexts_local.h"
 %include "../include/semanage/fcontexts_policy.h"
diff --git a/libsemanage/src/semanageswig_python.i b/libsemanage/src/semanageswig_python.i
index 1346b2ea..40932d8c 100644
--- a/libsemanage/src/semanageswig_python.i
+++ b/libsemanage/src/semanageswig_python.i
@@ -437,6 +437,49 @@
 	$1 = &temp;
 }
 
+/** ibpkey typemaps **/
+
+/* the wrapper will setup this parameter for passing... the resulting python functions
+   will not take the semanage_ibpkey_t *** parameter */
+%typemap(in, numinputs=0) semanage_ibpkey_t ***(semanage_ibpkey_t **temp=NULL) {
+	$1 = &temp;
+}
+
+%typemap(argout) (
+	semanage_handle_t* handle,
+	semanage_ibpkey_t*** records,
+	unsigned int* count) {
+
+	if ($result) {
+		int value;
+		SWIG_AsVal_int($result, &value);
+		if (value >= 0) {
+			PyObject* plist = NULL;
+			if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_ibpkey,
+				(void (*) (void*)) &semanage_ibpkey_free, &plist) < 0)
+				$result = SWIG_From_int(STATUS_ERR);
+			else
+				$result = SWIG_Python_AppendOutput($result, plist);
+		}
+	}
+}
+
+%typemap(in, numinputs=0) semanage_ibpkey_t **(semanage_ibpkey_t *temp=NULL) {
+	$1 = &temp;
+}
+
+%typemap(argout) semanage_ibpkey_t ** {
+	$result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
+}
+
+%typemap(argout) semanage_ibpkey_key_t ** {
+	$result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
+}
+
+%typemap(in, numinputs=0) semanage_ibpkey_key_t **(semanage_ibpkey_key_t *temp=NULL) {
+	$1 = &temp;
+}
+
 /** node typemaps **/
 
 /* the wrapper will setup this parameter for passing... the resulting python functions
diff --git a/libsemanage/utils/semanage_migrate_store b/libsemanage/utils/semanage_migrate_store
index 0ebd2852..325de47d 100755
--- a/libsemanage/utils/semanage_migrate_store
+++ b/libsemanage/utils/semanage_migrate_store
@@ -253,7 +253,8 @@ if __name__ == "__main__":
 		"preserve_tunables",
 		"policy.kern",
 		"file_contexts",
-		"homedir_template"]
+		"homedir_template",
+                "pkeys.local"]
 
 
 	create_dir(newroot_path(), 0o755)
diff --git a/libsepol/include/sepol/ibpkey_record.h b/libsepol/include/sepol/ibpkey_record.h
new file mode 100644
index 00000000..fff45910
--- /dev/null
+++ b/libsepol/include/sepol/ibpkey_record.h
@@ -0,0 +1,77 @@
+#ifndef _SEPOL_IBPKEY_RECORD_H_
+#define _SEPOL_IBPKEY_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+#define INET6_ADDRLEN 16
+
+__BEGIN_DECLS
+
+struct sepol_ibpkey;
+struct sepol_ibpkey_key;
+typedef struct sepol_ibpkey sepol_ibpkey_t;
+typedef struct sepol_ibpkey_key sepol_ibpkey_key_t;
+
+extern int sepol_ibpkey_compare(const sepol_ibpkey_t *ibpkey,
+				const sepol_ibpkey_key_t *key);
+
+extern int sepol_ibpkey_compare2(const sepol_ibpkey_t *ibpkey,
+				 const sepol_ibpkey_t *ibpkey2);
+
+extern int sepol_ibpkey_key_create(sepol_handle_t *handle,
+				   const char *subnet_prefix,
+				   int low, int high,
+				   sepol_ibpkey_key_t **key_ptr);
+
+extern void sepol_ibpkey_key_unpack(const sepol_ibpkey_key_t *key,
+				    const char **subnet_prefix,
+				    int *low, int *high);
+
+extern int sepol_ibpkey_key_extract(sepol_handle_t *handle,
+				    const sepol_ibpkey_t *ibpkey,
+				    sepol_ibpkey_key_t **key_ptr);
+
+extern void sepol_ibpkey_key_free(sepol_ibpkey_key_t *key);
+
+extern int sepol_ibpkey_get_low(const sepol_ibpkey_t *ibpkey);
+
+extern int sepol_ibpkey_get_high(const sepol_ibpkey_t *ibpkey);
+
+extern void sepol_ibpkey_set_pkey(sepol_ibpkey_t *ibpkey, int pkey_num);
+
+extern void sepol_ibpkey_set_range(sepol_ibpkey_t *ibpkey, int low, int high);
+
+extern int sepol_ibpkey_get_subnet_prefix(sepol_handle_t *handle,
+					  const sepol_ibpkey_t *ibpkey,
+					  char **subnet_prefix);
+
+extern int sepol_ibpkey_get_subnet_prefix_bytes(sepol_handle_t *handle,
+						const sepol_ibpkey_t *ibpkey,
+						char **buffer);
+
+extern int sepol_ibpkey_set_subnet_prefix(sepol_handle_t *handle,
+					  sepol_ibpkey_t *ibpkey,
+					  const char *subnet_prefix);
+
+extern int sepol_ibpkey_set_subnet_prefix_bytes(sepol_handle_t *handle,
+						sepol_ibpkey_t *ibpkey,
+						const char *subnet_prefix);
+
+extern sepol_context_t *sepol_ibpkey_get_con(const sepol_ibpkey_t *ibpkey);
+
+extern int sepol_ibpkey_set_con(sepol_handle_t *handle,
+				sepol_ibpkey_t *ibpkey, sepol_context_t *con);
+
+extern int sepol_ibpkey_create(sepol_handle_t *handle, sepol_ibpkey_t **ibpkey_ptr);
+
+extern int sepol_ibpkey_clone(sepol_handle_t *handle,
+			      const sepol_ibpkey_t *ibpkey,
+			      sepol_ibpkey_t **ibpkey_ptr);
+
+extern void sepol_ibpkey_free(sepol_ibpkey_t *ibpkey);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/ibpkeys.h b/libsepol/include/sepol/ibpkeys.h
new file mode 100644
index 00000000..4ab0a8a6
--- /dev/null
+++ b/libsepol/include/sepol/ibpkeys.h
@@ -0,0 +1,44 @@
+#ifndef _SEPOL_IBPKEYS_H_
+#define _SEPOL_IBPKEYS_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/ibpkey_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of ibpkeys */
+extern int sepol_ibpkey_count(sepol_handle_t *handle,
+			      const sepol_policydb_t *p, unsigned int *response);
+
+/* Check if a ibpkey exists */
+extern int sepol_ibpkey_exists(sepol_handle_t *handle,
+			       const sepol_policydb_t *policydb,
+			       const sepol_ibpkey_key_t *key, int *response);
+
+/* Query a ibpkey - returns the ibpkey, or NULL if not found */
+extern int sepol_ibpkey_query(sepol_handle_t *handle,
+			      const sepol_policydb_t *policydb,
+			      const sepol_ibpkey_key_t *key,
+			      sepol_ibpkey_t **response);
+
+/* Modify a ibpkey, or add it, if the key is not found */
+extern int sepol_ibpkey_modify(sepol_handle_t *handle,
+			       sepol_policydb_t *policydb,
+			       const sepol_ibpkey_key_t *key,
+			       const sepol_ibpkey_t *data);
+
+/* Iterate the ibpkeys
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue
+ */
+extern int sepol_ibpkey_iterate(sepol_handle_t *handle,
+				const sepol_policydb_t *policydb,
+				int (*fn)(const sepol_ibpkey_t *ibpkey,
+					  void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/sepol.h b/libsepol/include/sepol/sepol.h
index 513f77d7..540f01dc 100644
--- a/libsepol/include/sepol/sepol.h
+++ b/libsepol/include/sepol/sepol.h
@@ -11,12 +11,14 @@ extern "C" {
 #include <sepol/user_record.h>
 #include <sepol/context_record.h>
 #include <sepol/iface_record.h>
+#include <sepol/ibpkey_record.h>
 #include <sepol/port_record.h>
 #include <sepol/boolean_record.h>
 #include <sepol/node_record.h>
 
 #include <sepol/booleans.h>
 #include <sepol/interfaces.h>
+#include <sepol/ibpkeys.h>
 #include <sepol/ports.h>
 #include <sepol/nodes.h>
 #include <sepol/users.h>
diff --git a/libsepol/src/ibpkey_internal.h b/libsepol/src/ibpkey_internal.h
new file mode 100644
index 00000000..addf80a8
--- /dev/null
+++ b/libsepol/src/ibpkey_internal.h
@@ -0,0 +1,21 @@
+#ifndef _SEPOL_IBPKEY_INTERNAL_H_
+#define _SEPOL_IBPKEY_INTERNAL_H_
+
+#include <sepol/ibpkey_record.h>
+#include <sepol/ibpkeys.h>
+#include "dso.h"
+
+hidden_proto(sepol_ibpkey_create)
+hidden_proto(sepol_ibpkey_free)
+hidden_proto(sepol_ibpkey_get_con)
+hidden_proto(sepol_ibpkey_get_high)
+hidden_proto(sepol_ibpkey_get_low)
+hidden_proto(sepol_ibpkey_key_create)
+hidden_proto(sepol_ibpkey_key_unpack)
+hidden_proto(sepol_ibpkey_set_con)
+hidden_proto(sepol_ibpkey_set_range)
+hidden_proto(sepol_ibpkey_get_subnet_prefix)
+hidden_proto(sepol_ibpkey_get_subnet_prefix_bytes)
+hidden_proto(sepol_ibpkey_set_subnet_prefix)
+hidden_proto(sepol_ibpkey_set_subnet_prefix_bytes)
+#endif
diff --git a/libsepol/src/ibpkey_record.c b/libsepol/src/ibpkey_record.c
new file mode 100644
index 00000000..c551f411
--- /dev/null
+++ b/libsepol/src/ibpkey_record.c
@@ -0,0 +1,445 @@
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sepol/ibpkey_record.h>
+
+#include "ibpkey_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_ibpkey {
+	/* Subnet prefix */
+	char *subnet_prefix;
+
+	/* Low - High range. Same for single ibpkeys. */
+	int low, high;
+
+	/* Context */
+	sepol_context_t *con;
+};
+
+struct sepol_ibpkey_key {
+	/* Subnet prefix */
+	char *subnet_prefix;
+
+	/* Low - High range. Same for single ibpkeys. */
+	int low, high;
+};
+
+/* Converts a string represtation (subnet_prefix_str)
+ * to a numeric representation (subnet_prefix_bytes)
+ */
+static int ibpkey_parse_subnet_prefix(sepol_handle_t *handle,
+				      const char *subnet_prefix_str,
+				      char *subnet_prefix_bytes)
+{
+	struct in6_addr in_addr;
+
+	if (inet_pton(AF_INET6, subnet_prefix_str, &in_addr) <= 0) {
+		ERR(handle, "could not parse IPv6 address for ibpkey subnet prefix %s: %s",
+		    subnet_prefix_str, strerror(errno));
+		return STATUS_ERR;
+	}
+
+	memcpy(subnet_prefix_bytes, in_addr.s6_addr, sizeof(struct in6_addr));
+
+	return STATUS_SUCCESS;
+}
+
+static int ibpkey_alloc_subnet_prefix(sepol_handle_t *handle,
+				      char **subnet_prefix)
+{
+	char *tmp_subnet_prefix = malloc(sizeof(struct in6_addr));
+
+	if (!tmp_subnet_prefix)
+		goto omem;
+
+	*subnet_prefix = tmp_subnet_prefix;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+	return STATUS_ERR;
+}
+
+/* Converts a numeric representation (subnet_prefix_bytes)
+ * to a string representation (subnet_prefix_str)
+ */
+
+static int ibpkey_expand_subnet_prefix(sepol_handle_t *handle,
+				       char *subnet_prefix_bytes,
+				       char *subnet_prefix_str)
+{
+	struct in6_addr addr;
+
+	memset(&addr, 0, sizeof(struct in6_addr));
+	memcpy(&addr.s6_addr[0], subnet_prefix_bytes, 16);
+
+	if (inet_ntop(AF_INET6, &addr, subnet_prefix_str,
+		      INET6_ADDRSTRLEN) == NULL) {
+		ERR(handle,
+		    "could not expand IPv6 address to string: %s",
+		    strerror(errno));
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+/* Allocates a sufficiently large string (subnet_prefix)
+ * for an IPV6 address for the subnet prefix
+ */
+static int ibpkey_alloc_subnet_prefix_string(sepol_handle_t *handle,
+					     char **subnet_prefix)
+{
+	char *tmp_subnet_prefix = NULL;
+
+	tmp_subnet_prefix = malloc(INET6_ADDRSTRLEN);
+
+	if (!tmp_subnet_prefix)
+		goto omem;
+
+	*subnet_prefix = tmp_subnet_prefix;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+
+	ERR(handle, "could not allocate string buffer for subnet_prefix");
+	return STATUS_ERR;
+}
+
+/* Key */
+int sepol_ibpkey_key_create(sepol_handle_t *handle,
+			    const char *subnet_prefix,
+			    int low, int high,
+			    sepol_ibpkey_key_t **key_ptr)
+{
+	sepol_ibpkey_key_t *tmp_key =
+	    (sepol_ibpkey_key_t *)malloc(sizeof(sepol_ibpkey_key_t));
+
+	if (!tmp_key) {
+		ERR(handle, "out of memory, could not create ibpkey key");
+		goto omem;
+	}
+
+	if (ibpkey_alloc_subnet_prefix(handle, &tmp_key->subnet_prefix) < 0)
+		goto err;
+	if (ibpkey_parse_subnet_prefix(handle, subnet_prefix, tmp_key->subnet_prefix) < 0)
+		goto err;
+
+	tmp_key->low = low;
+	tmp_key->high = high;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+
+err:
+	sepol_ibpkey_key_free(tmp_key);
+	ERR(handle, "could not create ibpkey key for subnet prefix%s, range %u, %u",
+	    subnet_prefix, low, high);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_ibpkey_key_create)
+
+void sepol_ibpkey_key_unpack(const sepol_ibpkey_key_t *key,
+			     const char **subnet_prefix, int *low, int *high)
+{
+	*subnet_prefix = key->subnet_prefix;
+	*low = key->low;
+	*high = key->high;
+}
+
+hidden_def(sepol_ibpkey_key_unpack)
+
+int sepol_ibpkey_key_extract(sepol_handle_t *handle,
+			     const sepol_ibpkey_t *ibpkey,
+			     sepol_ibpkey_key_t **key_ptr)
+{
+	char subnet_prefix_str[INET6_ADDRSTRLEN];
+
+	ibpkey_expand_subnet_prefix(handle, ibpkey->subnet_prefix, subnet_prefix_str);
+
+	if (sepol_ibpkey_key_create
+	    (handle, subnet_prefix_str, ibpkey->low, ibpkey->high, key_ptr) < 0) {
+		ERR(handle, "could not extract key from ibpkey %s %d:%d",
+		    subnet_prefix_str,
+		    ibpkey->low, ibpkey->high);
+
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+void sepol_ibpkey_key_free(sepol_ibpkey_key_t *key)
+{
+	if (!key)
+		return;
+	free(key->subnet_prefix);
+	free(key);
+}
+
+int sepol_ibpkey_compare(const sepol_ibpkey_t *ibpkey, const sepol_ibpkey_key_t *key)
+{
+	int rc;
+
+	rc = memcmp(ibpkey->subnet_prefix, key->subnet_prefix, sizeof(struct in6_addr));
+
+	if (ibpkey->low == key->low &&
+	    ibpkey->high == key->high &&
+	    !rc)
+		return 0;
+
+	if (ibpkey->low < key->low)
+		return -1;
+
+	else if (key->low < ibpkey->low)
+		return 1;
+
+	else if (ibpkey->high < key->high)
+		return -1;
+
+	else if (key->high < ibpkey->high)
+		return 1;
+	else
+		return rc;
+}
+
+int sepol_ibpkey_compare2(const sepol_ibpkey_t *ibpkey, const sepol_ibpkey_t *ibpkey2)
+{
+	int rc;
+
+	rc = memcmp(ibpkey->subnet_prefix, ibpkey2->subnet_prefix, sizeof(struct in6_addr));
+
+	if (ibpkey->low == ibpkey2->low &&
+	    ibpkey->high == ibpkey2->high &&
+	    !rc)
+		return 0;
+
+	if (ibpkey->low < ibpkey2->low)
+		return -1;
+
+	else if (ibpkey2->low < ibpkey->low)
+		return 1;
+
+	else if (ibpkey->high < ibpkey2->high)
+		return -1;
+
+	else if (ibpkey2->high < ibpkey->high)
+		return 1;
+	else
+		return rc;
+}
+
+/* Pkey */
+int sepol_ibpkey_get_low(const sepol_ibpkey_t *ibpkey)
+{
+	return ibpkey->low;
+}
+
+hidden_def(sepol_ibpkey_get_low)
+
+int sepol_ibpkey_get_high(const sepol_ibpkey_t *ibpkey)
+{
+	return ibpkey->high;
+}
+
+hidden_def(sepol_ibpkey_get_high)
+
+void sepol_ibpkey_set_pkey(sepol_ibpkey_t *ibpkey, int pkey_num)
+{
+	ibpkey->low = pkey_num;
+	ibpkey->high = pkey_num;
+}
+
+void sepol_ibpkey_set_range(sepol_ibpkey_t *ibpkey, int low, int high)
+{
+	ibpkey->low = low;
+	ibpkey->high = high;
+}
+
+hidden_def(sepol_ibpkey_set_range)
+
+int sepol_ibpkey_get_subnet_prefix(sepol_handle_t *handle,
+				   const sepol_ibpkey_t *ibpkey,
+				   char **subnet_prefix)
+{
+	char *tmp_subnet_prefix = NULL;
+
+	if (ibpkey_alloc_subnet_prefix_string(handle, &tmp_subnet_prefix) < 0)
+		goto err;
+
+	if (ibpkey_expand_subnet_prefix(handle, ibpkey->subnet_prefix, tmp_subnet_prefix) < 0)
+		goto err;
+
+	*subnet_prefix = tmp_subnet_prefix;
+	return STATUS_SUCCESS;
+
+err:
+	free(tmp_subnet_prefix);
+	ERR(handle, "could not get ibpkey subnet_prefix");
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_ibpkey_get_subnet_prefix)
+
+/* Subnet prefix */
+int sepol_ibpkey_get_subnet_prefix_bytes(sepol_handle_t *handle,
+					 const sepol_ibpkey_t *ibpkey,
+					 char **buffer)
+{
+	char *tmp_buf = malloc(sizeof(struct in6_addr));
+
+	if (!tmp_buf) {
+		ERR(handle, "out of memory, could not get subnet prefix bytes");
+		return STATUS_ERR;
+	}
+
+	memcpy(tmp_buf, ibpkey->subnet_prefix, sizeof(struct in6_addr));
+	*buffer = tmp_buf;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_ibpkey_get_subnet_prefix_bytes)
+
+int sepol_ibpkey_set_subnet_prefix(sepol_handle_t *handle,
+				   sepol_ibpkey_t *ibpkey,
+				   const char *subnet_prefix)
+{
+	char *tmp = NULL;
+
+	if (ibpkey_alloc_subnet_prefix(handle, &tmp) < 0)
+		goto err;
+
+	if (ibpkey_parse_subnet_prefix(handle, subnet_prefix, tmp) < 0)
+		goto err;
+
+	free(ibpkey->subnet_prefix);
+	ibpkey->subnet_prefix = tmp;
+	return STATUS_SUCCESS;
+
+err:
+	free(tmp);
+	ERR(handle, "could not set ibpkey subnet prefix to %s", subnet_prefix);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_ibpkey_set_subnet_prefix)
+
+int sepol_ibpkey_set_subnet_prefix_bytes(sepol_handle_t *handle,
+					 sepol_ibpkey_t *ibpkey,
+					 const char *subnet_prefix)
+{
+	char *tmp_subnet_prefix = malloc(sizeof(struct in6_addr));
+
+	if (!tmp_subnet_prefix) {
+		ERR(handle, "out of memory, could not set ibpkey subnet prefix");
+		return STATUS_ERR;
+	}
+
+	memcpy(tmp_subnet_prefix, subnet_prefix, sizeof(struct in6_addr));
+	free(ibpkey->subnet_prefix);
+	ibpkey->subnet_prefix = tmp_subnet_prefix;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_ibpkey_set_subnet_prefix_bytes)
+
+/* Create */
+int sepol_ibpkey_create(sepol_handle_t *handle, sepol_ibpkey_t **ibpkey)
+{
+	sepol_ibpkey_t *tmp_ibpkey = (sepol_ibpkey_t *)malloc(sizeof(sepol_ibpkey_t));
+
+	if (!tmp_ibpkey) {
+		ERR(handle, "out of memory, could not create ibpkey record");
+		return STATUS_ERR;
+	}
+
+	tmp_ibpkey->subnet_prefix = NULL;
+	tmp_ibpkey->low = 0;
+	tmp_ibpkey->high = 0;
+	tmp_ibpkey->con = NULL;
+	*ibpkey = tmp_ibpkey;
+
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_ibpkey_create)
+
+/* Deep copy clone */
+int sepol_ibpkey_clone(sepol_handle_t *handle,
+		       const sepol_ibpkey_t *ibpkey, sepol_ibpkey_t **ibpkey_ptr)
+{
+	sepol_ibpkey_t *new_ibpkey = NULL;
+
+	if (sepol_ibpkey_create(handle, &new_ibpkey) < 0)
+		goto err;
+
+	new_ibpkey->subnet_prefix = malloc(sizeof(struct in6_addr));
+	if (!new_ibpkey->subnet_prefix)
+		goto omem;
+
+	memcpy(new_ibpkey->subnet_prefix, ibpkey->subnet_prefix, sizeof(struct in6_addr));
+	new_ibpkey->low = ibpkey->low;
+	new_ibpkey->high = ibpkey->high;
+
+	if (ibpkey->con &&
+	    (sepol_context_clone(handle, ibpkey->con, &new_ibpkey->con) < 0))
+		goto err;
+
+	*ibpkey_ptr = new_ibpkey;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+
+err:
+	ERR(handle, "could not clone ibpkey record");
+	sepol_ibpkey_free(new_ibpkey);
+	return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_ibpkey_free(sepol_ibpkey_t *ibpkey)
+{
+	if (!ibpkey)
+		return;
+
+	free(ibpkey->subnet_prefix);
+	sepol_context_free(ibpkey->con);
+	free(ibpkey);
+}
+
+hidden_def(sepol_ibpkey_free)
+
+/* Context */
+sepol_context_t *sepol_ibpkey_get_con(const sepol_ibpkey_t *ibpkey)
+{
+	return ibpkey->con;
+}
+
+hidden_def(sepol_ibpkey_get_con)
+
+int sepol_ibpkey_set_con(sepol_handle_t *handle,
+			 sepol_ibpkey_t *ibpkey, sepol_context_t *con)
+{
+	sepol_context_t *newcon;
+
+	if (sepol_context_clone(handle, con, &newcon) < 0) {
+		ERR(handle, "out of memory, could not set ibpkey context");
+		return STATUS_ERR;
+	}
+
+	sepol_context_free(ibpkey->con);
+	ibpkey->con = newcon;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_ibpkey_set_con)
diff --git a/libsepol/src/ibpkeys.c b/libsepol/src/ibpkeys.c
new file mode 100644
index 00000000..ab2086d0
--- /dev/null
+++ b/libsepol/src/ibpkeys.c
@@ -0,0 +1,269 @@
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/ibpkey_record.h>
+#include <sepol/policydb/policydb.h>
+#include "ibpkey_internal.h"
+
+/* Create a low level ibpkey structure from
+ * a high level representation
+ */
+static int ibpkey_from_record(sepol_handle_t *handle,
+			      const policydb_t *policydb,
+			      ocontext_t **ibpkey, const sepol_ibpkey_t *data)
+{
+	ocontext_t *tmp_ibpkey = NULL;
+	context_struct_t *tmp_con = NULL;
+	char *subnet_prefix_buf = NULL;
+	int low = sepol_ibpkey_get_low(data);
+	int high = sepol_ibpkey_get_high(data);
+
+	tmp_ibpkey = (ocontext_t *)calloc(1, sizeof(*tmp_ibpkey));
+	if (!tmp_ibpkey)
+		goto omem;
+
+	if (sepol_ibpkey_get_subnet_prefix_bytes(handle,
+						 data,
+						 &subnet_prefix_buf) < 0)
+		goto err;
+
+	memcpy(&tmp_ibpkey->u.ibpkey.subnet_prefix, subnet_prefix_buf,
+	       sizeof(tmp_ibpkey->u.ibpkey.subnet_prefix));
+
+	free(subnet_prefix_buf);
+	subnet_prefix_buf = NULL;
+
+	/* Pkey range */
+	tmp_ibpkey->u.ibpkey.low_pkey = low;
+	tmp_ibpkey->u.ibpkey.high_pkey = high;
+	if (tmp_ibpkey->u.ibpkey.low_pkey > tmp_ibpkey->u.ibpkey.high_pkey) {
+		ERR(handle, "low ibpkey %d exceeds high ibpkey %d",
+		    tmp_ibpkey->u.ibpkey.low_pkey, tmp_ibpkey->u.ibpkey.high_pkey);
+		goto err;
+	}
+
+	/* Context */
+	if (context_from_record(handle, policydb, &tmp_con,
+				sepol_ibpkey_get_con(data)) < 0)
+		goto err;
+	context_cpy(&tmp_ibpkey->context[0], tmp_con);
+	context_destroy(tmp_con);
+	free(tmp_con);
+	tmp_con = NULL;
+
+	*ibpkey = tmp_ibpkey;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+
+err:
+	if (tmp_ibpkey) {
+		context_destroy(&tmp_ibpkey->context[0]);
+		free(tmp_ibpkey);
+	}
+	context_destroy(tmp_con);
+	free(tmp_con);
+	free(subnet_prefix_buf);
+	ERR(handle, "could not create ibpkey structure");
+	return STATUS_ERR;
+}
+
+static int ibpkey_to_record(sepol_handle_t *handle,
+			    const policydb_t *policydb,
+			    ocontext_t *ibpkey, sepol_ibpkey_t **record)
+{
+	int low = ibpkey->u.ibpkey.low_pkey;
+	int high = ibpkey->u.ibpkey.high_pkey;
+	struct in6_addr subnet_prefix = {0};
+	context_struct_t *con = &ibpkey->context[0];
+
+	sepol_context_t *tmp_con = NULL;
+	sepol_ibpkey_t *tmp_record = NULL;
+
+	if (sepol_ibpkey_create(handle, &tmp_record) < 0)
+		goto err;
+
+	memcpy(&subnet_prefix.s6_addr, &ibpkey->u.ibpkey.subnet_prefix,
+	       sizeof(ibpkey->u.ibpkey.subnet_prefix));
+
+	if (sepol_ibpkey_set_subnet_prefix_bytes(handle, tmp_record,
+						 (const char *)subnet_prefix.s6_addr) < 0)
+		goto err;
+
+	sepol_ibpkey_set_range(tmp_record, low, high);
+
+	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+		goto err;
+
+	if (sepol_ibpkey_set_con(handle, tmp_record, tmp_con) < 0)
+		goto err;
+
+	sepol_context_free(tmp_con);
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not convert ibpkey to record");
+	sepol_context_free(tmp_con);
+	sepol_ibpkey_free(tmp_record);
+	return STATUS_ERR;
+}
+
+/* Return the number of ibpkeys */
+extern int sepol_ibpkey_count(sepol_handle_t *handle __attribute__ ((unused)),
+			      const sepol_policydb_t *p, unsigned int *response)
+{
+	unsigned int count = 0;
+	ocontext_t *c, *head;
+	const policydb_t *policydb = &p->p;
+
+	head = policydb->ocontexts[OCON_IBPKEY];
+	for (c = head; c; c = c->next)
+		count++;
+
+	*response = count;
+
+	handle = NULL;
+	return STATUS_SUCCESS;
+}
+
+/* Check if a ibpkey exists */
+int sepol_ibpkey_exists(sepol_handle_t *handle __attribute__ ((unused)),
+			const sepol_policydb_t *p,
+			const sepol_ibpkey_key_t *key, int *response)
+{
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	int low, high;
+	const char *subnet_prefix;
+
+	sepol_ibpkey_key_unpack(key, &subnet_prefix, &low, &high);
+
+	head = policydb->ocontexts[OCON_IBPKEY];
+	for (c = head; c; c = c->next) {
+		uint64_t subnet_prefix2 = c->u.ibpkey.subnet_prefix;
+		uint16_t low2 = c->u.ibpkey.low_pkey;
+		uint16_t high2 = c->u.ibpkey.high_pkey;
+
+		if (low2 == low &&
+		    high2 == high &&
+		    (!memcmp(subnet_prefix, &subnet_prefix2,
+			     sizeof(subnet_prefix2)))) {
+			*response = 1;
+			return STATUS_SUCCESS;
+		}
+	}
+
+	*response = 0;
+	return STATUS_SUCCESS;
+}
+
+/* Query a ibpkey */
+int sepol_ibpkey_query(sepol_handle_t *handle,
+		       const sepol_policydb_t *p,
+		       const sepol_ibpkey_key_t *key, sepol_ibpkey_t **response)
+{
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	int low, high;
+	const char *subnet_prefix;
+
+	sepol_ibpkey_key_unpack(key, &subnet_prefix, &low, &high);
+
+	head = policydb->ocontexts[OCON_IBPKEY];
+	for (c = head; c; c = c->next) {
+		uint64_t subnet_prefix2 = c->u.ibpkey.subnet_prefix;
+		int low2 = c->u.ibpkey.low_pkey;
+		int high2 = c->u.ibpkey.high_pkey;
+
+		if (low2 == low &&
+		    high2 == high &&
+		    (!memcmp(subnet_prefix, &subnet_prefix2,
+			     sizeof(subnet_prefix2)))) {
+			if (ibpkey_to_record(handle, policydb, c, response) < 0)
+				goto err;
+			return STATUS_SUCCESS;
+		}
+	}
+
+	*response = NULL;
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not query ibpkey subnet prefix: %s range %u - %u exists",
+	    subnet_prefix, low, high);
+	return STATUS_ERR;
+}
+
+/* Load a ibpkey into policy */
+int sepol_ibpkey_modify(sepol_handle_t *handle,
+			sepol_policydb_t *p,
+			const sepol_ibpkey_key_t *key, const sepol_ibpkey_t *data)
+{
+	policydb_t *policydb = &p->p;
+	ocontext_t *ibpkey = NULL;
+	int low, high;
+	const char *subnet_prefix;
+
+	sepol_ibpkey_key_unpack(key, &subnet_prefix, &low, &high);
+
+	if (ibpkey_from_record(handle, policydb, &ibpkey, data) < 0)
+		goto err;
+
+	/* Attach to context list */
+	ibpkey->next = policydb->ocontexts[OCON_IBPKEY];
+	policydb->ocontexts[OCON_IBPKEY] = ibpkey;
+
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not load ibpkey subnet prefix: %s range %u - %u exists",
+	    subnet_prefix, low, high);
+	if (ibpkey) {
+		context_destroy(&ibpkey->context[0]);
+		free(ibpkey);
+	}
+	return STATUS_ERR;
+}
+
+int sepol_ibpkey_iterate(sepol_handle_t *handle,
+			 const sepol_policydb_t *p,
+			 int (*fn)(const sepol_ibpkey_t *ibpkey,
+				   void *fn_arg), void *arg)
+{
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	sepol_ibpkey_t *ibpkey = NULL;
+
+	head = policydb->ocontexts[OCON_IBPKEY];
+	for (c = head; c; c = c->next) {
+		int status;
+
+		if (ibpkey_to_record(handle, policydb, c, &ibpkey) < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(ibpkey, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_ibpkey_free(ibpkey);
+		ibpkey = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not iterate over ibpkeys");
+	sepol_ibpkey_free(ibpkey);
+	return STATUS_ERR;
+}
diff --git a/python/semanage/semanage b/python/semanage/semanage
index 9659aac9..11b56e22 100644
--- a/python/semanage/semanage
+++ b/python/semanage/semanage
@@ -58,6 +58,9 @@ usage_user_dict = {' --add': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', '-s SEUSE
 usage_port = "semanage port [-h] [-n] [-N] [-S STORE] ["
 usage_port_dict = {' --add': ('-t TYPE', '-p PROTOCOL', '-r RANGE', '(', 'port_name', '|', 'port_range', ')'), ' --modify': ('-t TYPE', '-p PROTOCOL', '-r RANGE', '(', 'port_name', '|', 'port_range', ')'), ' --delete': ('-p PROTOCOL', '(', 'port_name', '|', 'port_range', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
 
+usage_ibpkey = "semanage ibpkey [-h] [-n] [-N] [-s STORE] ["
+usage_ibpkey_dict = {' --add': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --modify': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --delete': ('-x SUBNET_PREFIX', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
+
 usage_node = "semanage node [-h] [-n] [-N] [-S STORE] ["
 usage_node_dict = {' --add': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --modify': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --delete': ('-M NETMASK', '-p PROTOCOL', 'node'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
 
@@ -145,6 +148,9 @@ def port_ini():
     OBJECT = seobject.portRecords(store)
     return OBJECT
 
+def ibpkey_ini():
+    OBJECT = seobject.ibpkeyRecords(store)
+    return OBJECT
 
 def module_ini():
     OBJECT = seobject.moduleRecords(store)
@@ -181,7 +187,7 @@ def dontaudit_ini():
     return OBJECT
 
 # define dictonary for seobject OBEJCTS
-object_dict = {'login': login_ini, 'user': user_ini, 'port': port_ini, 'module': module_ini, 'interface': interface_ini, 'node': node_ini, 'fcontext': fcontext_ini, 'boolean': boolean_ini, 'permissive': permissive_ini, 'dontaudit': dontaudit_ini}
+object_dict = {'login': login_ini, 'user': user_ini, 'port': port_ini, 'module': module_ini, 'interface': interface_ini, 'node': node_ini, 'fcontext': fcontext_ini, 'boolean': boolean_ini, 'permissive': permissive_ini, 'dontaudit': dontaudit_ini, 'ibpkey': ibpkey_ini}
 
 
 def generate_custom_usage(usage_text, usage_dict):
@@ -292,6 +298,11 @@ def parser_add_proto(parser, name):
     version for the specified node (ipv4|ipv6).
 '''))
 
+def parser_add_subnet_prefix(parser, name):
+    parser.add_argument('-x', '--subnet_prefix', help=_('''
+    Subnet prefix for  the specified infiniband ibpkey.
+'''))
+
 
 def parser_add_modify(parser, name):
     parser.add_argument('-m', '--modify', dest='action', action='store_const', const='modify', help=_("Modify a record of the %s object type") % name)
@@ -511,6 +522,52 @@ def setupPortParser(subparsers):
     portParser.set_defaults(func=handlePort)
 
 
+
+def handlePkey(args):
+    ibpkey_args = {'list': [('ibpkey', 'type', 'subnet_prefix'), ('')], 'add': [('locallist'), ('type', 'ibpkey', 'subnet_prefix')], 'modify': [('localist'), ('ibpkey', 'subnet_prefix')], 'delete': [('locallist'), ('ibpkey', 'subnet_prefix')], 'extract': [('locallist', 'ibpkey', 'type', 'subnet prefix'), ('')], 'deleteall': [('locallist'), ('')]}
+
+    handle_opts(args, ibpkey_args, args.action)
+
+    OBJECT = object_dict['ibpkey']()
+    OBJECT.set_reload(args.noreload)
+
+    if args.action is "add":
+        OBJECT.add(args.ibpkey, args.subnet_prefix, args.range, args.type)
+    if args.action is "modify":
+        OBJECT.modify(args.ibpkey, args.subnet_prefix, args.range, args.type)
+    if args.action is "delete":
+        OBJECT.delete(args.ibpkey, args.subnet_prefix)
+    if args.action is "list":
+        OBJECT.list(args.noheading, args.locallist)
+    if args.action is "deleteall":
+        OBJECT.deleteall()
+    if args.action is "extract":
+        for i in OBJECT.customized():
+            print("ibpkey %s" % str(i))
+
+
+def setupPkeyParser(subparsers):
+    generated_usage = generate_custom_usage(usage_ibpkey, usage_ibpkey_dict)
+    ibpkeyParser = subparsers.add_parser('ibpkey', usage=generated_usage, help=_('Manage infiniband ibpkey type definitions'))
+    parser_add_locallist(ibpkeyParser, "ibpkey")
+    parser_add_noheading(ibpkeyParser, "ibpkey")
+    parser_add_noreload(ibpkeyParser, "ibpkey")
+    parser_add_store(ibpkeyParser, "ibpkey")
+
+    ibpkey_action = ibpkeyParser.add_mutually_exclusive_group(required=True)
+    parser_add_add(ibpkey_action, "ibpkey")
+    parser_add_delete(ibpkey_action, "ibpkey")
+    parser_add_modify(ibpkey_action, "ibpkey")
+    parser_add_list(ibpkey_action, "ibpkey")
+    parser_add_extract(ibpkey_action, "ibpkey")
+    parser_add_deleteall(ibpkey_action, "ibpkey")
+    parser_add_type(ibpkeyParser, "ibpkey")
+    parser_add_range(ibpkeyParser, "ibpkey")
+    parser_add_subnet_prefix(ibpkeyParser, "ibpkey")
+    ibpkeyParser.add_argument('ibpkey', nargs='?', default=None, help=_('pkey | pkey_range'))
+    ibpkeyParser.set_defaults(func=handlePkey)
+
+
 def handleInterface(args):
     interface_args = {'list': [('interface'), ('')], 'add': [('locallist'), ('type', 'interface')], 'modify': [('locallist'), ('type', 'interface')], 'delete': [('locallist'), ('interface')], 'extract': [('locallist', 'interface', 'type'), ('')], 'deleteall': [('locallist'), ('')]}
 
@@ -849,6 +906,7 @@ def createCommandParser():
     setupLoginParser(subparsers)
     setupUserParser(subparsers)
     setupPortParser(subparsers)
+    setupPkeyParser(subparsers)
     setupInterfaceParser(subparsers)
     setupModuleParser(subparsers)
     setupNodeParser(subparsers)
diff --git a/python/semanage/seobject.py b/python/semanage/seobject.py
index 7a543733..297a2496 100644
--- a/python/semanage/seobject.py
+++ b/python/semanage/seobject.py
@@ -32,6 +32,7 @@ import socket
 from semanage import *
 PROGNAME = "policycoreutils"
 import sepolicy
+import setools
 from IPy import IP
 
 try:
@@ -1309,6 +1310,260 @@ class portRecords(semanageRecords):
                 rec += ", %s" % p
             print(rec)
 
+class ibpkeyRecords(semanageRecords):
+    try:
+        q = setools.TypeQuery(setools.SELinuxPolicy(sepolicy.get_installed_policy()), attrs=["ibpkey_type"])
+        valid_types = sorted(str(t) for t in q.results())
+    except:
+        valid_types = []
+
+    def __init__(self, store=""):
+        semanageRecords.__init__(self, store)
+
+    def __genkey(self, pkey, subnet_prefix):
+	if subnet_prefix == "":
+            raise ValueError(_("Subnet Prefix is required"))
+
+	pkeys = pkey.split("-")
+        if len(pkeys) == 1:
+            high = low = int(pkeys[0], 0)
+        else:
+            low = int(pkeys[0], 0)
+            high = int(pkeys[1], 0)
+
+        if high > 65535:
+            raise ValueError(_("Invalid Pkey"))
+
+        (rc, k) = semanage_ibpkey_key_create(self.sh, subnet_prefix, low, high)
+        if rc < 0:
+            raise ValueError(_("Could not create a key for %s/%s") % (subnet_prefix, pkey))
+        return (k, subnet_prefix, low, high)
+
+    def __add(self, pkey, subnet_prefix, serange, type):
+        if is_mls_enabled == 1:
+            if serange == "":
+                serange = "s0"
+            else:
+                serange = untranslate(serange)
+
+        if type == "":
+            raise ValueError(_("Type is required"))
+
+        if type not in self.valid_types:
+            raise ValueError(_("Type %s is invalid, must be a ibpkey type") % type)
+
+        (k, subnet_prefix, low, high) = self.__genkey(pkey, subnet_prefix)
+
+        (rc, exists) = semanage_ibpkey_exists(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibpkey %s/%s is defined") % (subnet_prefix, pkey))
+        if exists:
+            raise ValueError(_("ibpkey %s/%s already defined") % (subnet_prefix, pkey))
+
+        (rc, p) = semanage_ibpkey_create(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not create ibpkey for %s/%s") % (subnet_prefix, pkey))
+
+        semanage_ibpkey_set_subnet_prefix(self.sh, p, subnet_prefix)
+        semanage_ibpkey_set_range(p, low, high)
+        (rc, con) = semanage_context_create(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not create context for %s/%s") % (subnet_prefix, pkey))
+
+        rc = semanage_context_set_user(self.sh, con, "system_u")
+        if rc < 0:
+            raise ValueError(_("Could not set user in ibpkey context for %s/%s") % (subnet_prefix, pkey))
+
+        rc = semanage_context_set_role(self.sh, con, "object_r")
+        if rc < 0:
+            raise ValueError(_("Could not set role in ibpkey context for %s/%s") % (subnet_prefix, pkey))
+
+        rc = semanage_context_set_type(self.sh, con, type)
+        if rc < 0:
+            raise ValueError(_("Could not set type in ibpkey context for %s/%s") % (subnet_prefix, pkey))
+
+        if (is_mls_enabled == 1) and (serange != ""):
+            rc = semanage_context_set_mls(self.sh, con, serange)
+            if rc < 0:
+                raise ValueError(_("Could not set mls fields in ibpkey context for %s/%s") % (subnet_prefix, pkey))
+
+        rc = semanage_ibpkey_set_con(self.sh, p, con)
+        if rc < 0:
+            raise ValueError(_("Could not set ibpkey context for %s/%s") % (subnet_prefix, pkey))
+
+        rc = semanage_ibpkey_modify_local(self.sh, k, p)
+        if rc < 0:
+            raise ValueError(_("Could not add ibpkey %s/%s") % (subnet_prefix, pkey))
+
+        semanage_context_free(con)
+        semanage_ibpkey_key_free(k)
+        semanage_ibpkey_free(p)
+
+    def add(self, pkey, subnet_prefix, serange, type):
+        self.begin()
+        self.__add(pkey, subnet_prefix, serange, type)
+        self.commit()
+
+    def __modify(self, pkey, subnet_prefix, serange, setype):
+        if serange == "" and setype == "":
+            if is_mls_enabled == 1:
+                raise ValueError(_("Requires setype or serange"))
+            else:
+                raise ValueError(_("Requires setype"))
+
+        if setype and setype not in self.valid_types:
+            raise ValueError(_("Type %s is invalid, must be a ibpkey type") % setype)
+
+        (k, subnet_prefix, low, high) = self.__genkey(pkey, subnet_prefix)
+
+        (rc, exists) = semanage_ibpkey_exists(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibpkey %s/%s is defined") % (subnet_prefix, pkey))
+        if not exists:
+            raise ValueError(_("ibpkey %s/%s is not defined") % (subnet_prefix, pkey))
+
+        (rc, p) = semanage_ibpkey_query(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not query ibpkey %s/%s") % (subnet_prefix, pkey))
+
+        con = semanage_ibpkey_get_con(p)
+
+        if (is_mls_enabled == 1) and (serange != ""):
+            semanage_context_set_mls(self.sh, con, untranslate(serange))
+        if setype != "":
+            semanage_context_set_type(self.sh, con, setype)
+
+        rc = semanage_ibpkey_modify_local(self.sh, k, p)
+        if rc < 0:
+            raise ValueError(_("Could not modify ibpkey %s/%s") % (subnet_prefix, pkey))
+
+        semanage_ibpkey_key_free(k)
+        semanage_ibpkey_free(p)
+
+    def modify(self, pkey, subnet_prefix, serange, setype):
+        self.begin()
+        self.__modify(pkey, subnet_prefix, serange, setype)
+        self.commit()
+
+    def deleteall(self):
+        (rc, plist) = semanage_ibpkey_list_local(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not list the ibpkeys"))
+
+        self.begin()
+
+        for ibpkey in plist:
+            (rc, subnet_prefix) = semanage_ibpkey_get_subnet_prefix(self.sh, ibpkey)
+            low = semanage_ibpkey_get_low(ibpkey)
+            high = semanage_ibpkey_get_high(ibpkey)
+            pkey_str = "%s-%s" % (low, high)
+            (k, subnet_prefix, low, high) = self.__genkey(pkey_str, subnet_prefix)
+            if rc < 0:
+                raise ValueError(_("Could not create a key for %s") % pkey_str)
+
+            rc = semanage_ibpkey_del_local(self.sh, k)
+            if rc < 0:
+                raise ValueError(_("Could not delete the ibpkey %s") % pkey_str)
+            semanage_ibpkey_key_free(k)
+
+        self.commit()
+
+    def __delete(self, pkey, subnet_prefix):
+        (k, subnet_prefix, low, high) = self.__genkey(pkey, subnet_prefix)
+        (rc, exists) = semanage_ibpkey_exists(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibpkey %s/%s is defined") % (subnet_prefix, pkey))
+        if not exists:
+            raise ValueError(_("ibpkey %s/%s is not defined") % (subnet_prefix, pkey))
+
+        (rc, exists) = semanage_ibpkey_exists_local(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibpkey %s/%s is defined") % (subnet_prefix, pkey))
+        if not exists:
+            raise ValueError(_("ibpkey %s/%s is defined in policy, cannot be deleted") % (subnet_prefix, pkey))
+
+        rc = semanage_ibpkey_del_local(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not delete ibpkey %s/%s") % (subnet_prefix, pkey))
+
+        semanage_ibpkey_key_free(k)
+
+    def delete(self, pkey, subnet_prefix):
+        self.begin()
+        self.__delete(pkey, subnet_prefix)
+        self.commit()
+
+    def get_all(self, locallist=0):
+        ddict = {}
+        if locallist:
+            (rc, self.plist) = semanage_ibpkey_list_local(self.sh)
+        else:
+            (rc, self.plist) = semanage_ibpkey_list(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not list ibpkeys"))
+
+        for ibpkey in self.plist:
+            con = semanage_ibpkey_get_con(ibpkey)
+            ctype = semanage_context_get_type(con)
+            if ctype == "reserved_ibpkey_t":
+                continue
+            level = semanage_context_get_mls(con)
+            (rc, subnet_prefix) = semanage_ibpkey_get_subnet_prefix(self.sh, ibpkey)
+            low = semanage_ibpkey_get_low(ibpkey)
+            high = semanage_ibpkey_get_high(ibpkey)
+            ddict[(low, high, subnet_prefix)] = (ctype, level)
+        return ddict
+
+    def get_all_by_type(self, locallist=0):
+        ddict = {}
+        if locallist:
+            (rc, self.plist) = semanage_ibpkey_list_local(self.sh)
+        else:
+            (rc, self.plist) = semanage_ibpkey_list(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not list ibpkeys"))
+
+        for ibpkey in self.plist:
+            con = semanage_ibpkey_get_con(ibpkey)
+            ctype = semanage_context_get_type(con)
+            (rc, subnet_prefix) = semanage_ibpkey_get_subnet_prefix(self.sh, ibpkey)
+            low = semanage_ibpkey_get_low(ibpkey)
+            high = semanage_ibpkey_get_high(ibpkey)
+            if (ctype, subnet_prefix) not in ddict.keys():
+                ddict[(ctype, subnet_prefix)] = []
+            if low == high:
+                ddict[(ctype, subnet_prefix)].append("0x%x" % low)
+            else:
+                ddict[(ctype, subnet_prefix)].append("0x%x-0x%x" % (low, high))
+        return ddict
+
+    def customized(self):
+        l = []
+        ddict = self.get_all(True)
+        keys = ddict.keys()
+        keys.sort()
+        for k in keys:
+            if k[0] == k[1]:
+                l.append("-a -t %s -x %s %s" % (ddict[k][0], k[2], k[0]))
+            else:
+                l.append("-a -t %s -x %s %s-%s" % (ddict[k][0], k[2], k[0], k[1]))
+        return l
+
+    def list(self, heading=1, locallist=0):
+        ddict = self.get_all_by_type(locallist)
+        keys = ddict.keys()
+        if len(keys) == 0:
+            return
+        keys.sort()
+
+        if heading:
+            print "%-30s %-18s %s\n" % (_("SELinux IB Pkey Type"), _("Subnet_Prefix"), _("Pkey Number"))
+        for i in keys:
+            rec = "%-30s %-18s " % i
+            rec += "%s" % ddict[i][0]
+            for p in ddict[i][1:]:
+                rec += ", %s" % p
+            print rec
 
 class nodeRecords(semanageRecords):
     try:
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 8/9] semanage: Update semanage to allow runtime labeling of ibendports
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
                   ` (6 preceding siblings ...)
  2017-05-18 22:25 ` [PATCH v2 7/9] semanage: Update semanage to allow runtime labeling of Infiniband Pkeys Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  2017-05-18 22:25 ` [PATCH v2 9/9] semanage: Update man pages for infiniband Dan Jurgens
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Update libsepol and libsemanage to work with ibendport records. Add local
storage for new and modified ibendport records in ibendports.local.
Update semanage to parse the ibendport command options to add, modify,
and delete them.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>

---
v1:
Jason Zaman:
- Use SETools directly to query types in seobject.py

v2:
Jason Zaman:
- Use set instead of sorted for valid_types.

Stephen Smalley:
- Fix semanage when ibendport_type attribute isn't defined.
---
 libsemanage/include/semanage/ibendport_record.h  |  62 +++++
 libsemanage/include/semanage/ibendports_local.h  |  36 +++
 libsemanage/include/semanage/ibendports_policy.h |  28 +++
 libsemanage/include/semanage/semanage.h          |   3 +
 libsemanage/src/direct_api.c                     |  40 ++-
 libsemanage/src/handle.h                         |  38 ++-
 libsemanage/src/ibendport_internal.h             |  48 ++++
 libsemanage/src/ibendport_record.c               | 154 ++++++++++++
 libsemanage/src/ibendports_file.c                | 157 ++++++++++++
 libsemanage/src/ibendports_local.c               | 153 ++++++++++++
 libsemanage/src/ibendports_policy.c              |  55 +++++
 libsemanage/src/ibendports_policydb.c            |  62 +++++
 libsemanage/src/libsemanage.map                  |   1 +
 libsemanage/src/policy_components.c              |   4 +
 libsemanage/src/semanage_store.c                 |   1 +
 libsemanage/src/semanage_store.h                 |   1 +
 libsemanage/src/semanageswig.i                   |   3 +
 libsemanage/src/semanageswig_python.i            |  43 ++++
 libsemanage/utils/semanage_migrate_store         |   3 +-
 libsepol/include/sepol/ibendport_record.h        |  68 ++++++
 libsepol/include/sepol/ibendports.h              |  45 ++++
 libsepol/include/sepol/sepol.h                   |   2 +
 libsepol/src/ibendport_internal.h                |  18 ++
 libsepol/src/ibendport_record.c                  | 298 +++++++++++++++++++++++
 libsepol/src/ibendports.c                        | 255 +++++++++++++++++++
 python/semanage/semanage                         |  58 ++++-
 python/semanage/seobject.py                      | 239 ++++++++++++++++++
 27 files changed, 1854 insertions(+), 21 deletions(-)
 create mode 100644 libsemanage/include/semanage/ibendport_record.h
 create mode 100644 libsemanage/include/semanage/ibendports_local.h
 create mode 100644 libsemanage/include/semanage/ibendports_policy.h
 create mode 100644 libsemanage/src/ibendport_internal.h
 create mode 100644 libsemanage/src/ibendport_record.c
 create mode 100644 libsemanage/src/ibendports_file.c
 create mode 100644 libsemanage/src/ibendports_local.c
 create mode 100644 libsemanage/src/ibendports_policy.c
 create mode 100644 libsemanage/src/ibendports_policydb.c
 create mode 100644 libsepol/include/sepol/ibendport_record.h
 create mode 100644 libsepol/include/sepol/ibendports.h
 create mode 100644 libsepol/src/ibendport_internal.h
 create mode 100644 libsepol/src/ibendport_record.c
 create mode 100644 libsepol/src/ibendports.c

diff --git a/libsemanage/include/semanage/ibendport_record.h b/libsemanage/include/semanage/ibendport_record.h
new file mode 100644
index 00000000..153eea02
--- /dev/null
+++ b/libsemanage/include/semanage/ibendport_record.h
@@ -0,0 +1,62 @@
+/*Copyright (C) 2005 Red Hat, Inc. */
+
+#ifndef _SEMANAGE_IBENDPORT_RECORD_H_
+#define _SEMANAGE_IBENDPORT_RECORD_H_
+
+#include <semanage/context_record.h>
+#include <semanage/handle.h>
+#include <stddef.h>
+
+#ifndef _SEMANAGE_IBENDPORT_DEFINED_
+struct semanage_ibendport;
+struct semanage_ibendport_key;
+typedef struct semanage_ibendport semanage_ibendport_t;
+typedef struct semanage_ibendport_key semanage_ibendport_key_t;
+#define _SEMANAGE_IBENDPORT_DEFINED_
+#endif
+
+extern int semanage_ibendport_compare(const semanage_ibendport_t *ibendport,
+				      const semanage_ibendport_key_t *key);
+
+extern int semanage_ibendport_compare2(const semanage_ibendport_t *ibendport,
+				       const semanage_ibendport_t *ibendport2);
+
+extern int semanage_ibendport_key_create(semanage_handle_t *handle,
+					 const char *ibdev_name,
+					 int port,
+					 semanage_ibendport_key_t **key_ptr);
+
+extern int semanage_ibendport_key_extract(semanage_handle_t *handle,
+					  const semanage_ibendport_t *ibendport,
+					  semanage_ibendport_key_t **key_ptr);
+
+extern void semanage_ibendport_key_free(semanage_ibendport_key_t *key);
+
+extern int semanage_ibendport_get_ibdev_name(semanage_handle_t *handle,
+					     const semanage_ibendport_t *ibendport,
+					     char **ibdev_name_ptr);
+
+extern int semanage_ibendport_set_ibdev_name(semanage_handle_t *handle,
+					     semanage_ibendport_t *ibendport,
+					     const char *ibdev_name);
+
+extern int semanage_ibendport_get_port(const semanage_ibendport_t *ibendport);
+
+extern void semanage_ibendport_set_port(semanage_ibendport_t *ibendport, int port);
+
+extern semanage_context_t *semanage_ibendport_get_con(const semanage_ibendport_t *ibendport);
+
+extern int semanage_ibendport_set_con(semanage_handle_t *handle,
+				      semanage_ibendport_t *ibendport,
+				      semanage_context_t *con);
+
+extern int semanage_ibendport_create(semanage_handle_t *handle,
+				     semanage_ibendport_t **ibendport_ptr);
+
+extern int semanage_ibendport_clone(semanage_handle_t *handle,
+				    const semanage_ibendport_t *ibendport,
+				    semanage_ibendport_t **ibendport_ptr);
+
+extern void semanage_ibendport_free(semanage_ibendport_t *ibendport);
+
+#endif
diff --git a/libsemanage/include/semanage/ibendports_local.h b/libsemanage/include/semanage/ibendports_local.h
new file mode 100644
index 00000000..641dd351
--- /dev/null
+++ b/libsemanage/include/semanage/ibendports_local.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc */
+
+#ifndef _SEMANAGE_IBENDPORTS_LOCAL_H_
+#define _SEMANAGE_IBENDPORTS_LOCAL_H_
+
+#include <semanage/ibendport_record.h>
+#include <semanage/handle.h>
+
+extern int semanage_ibendport_modify_local(semanage_handle_t *handle,
+					   const semanage_ibendport_key_t *key,
+					   const semanage_ibendport_t *data);
+
+extern int semanage_ibendport_del_local(semanage_handle_t *handle,
+					const semanage_ibendport_key_t *key);
+
+extern int semanage_ibendport_query_local(semanage_handle_t *handle,
+					  const semanage_ibendport_key_t *key,
+					  semanage_ibendport_t **response);
+
+extern int semanage_ibendport_exists_local(semanage_handle_t *handle,
+					   const semanage_ibendport_key_t *key,
+					   int *response);
+
+extern int semanage_ibendport_count_local(semanage_handle_t *handle,
+					  unsigned int *response);
+
+extern int semanage_ibendport_iterate_local(semanage_handle_t *handle,
+					    int (*handler)(const semanage_ibendport_t *record,
+							   void *varg),
+					    void *handler_arg);
+
+extern int semanage_ibendport_list_local(semanage_handle_t *handle,
+					 semanage_ibendport_t ***records,
+					 unsigned int *count);
+
+#endif
diff --git a/libsemanage/include/semanage/ibendports_policy.h b/libsemanage/include/semanage/ibendports_policy.h
new file mode 100644
index 00000000..3fc1976d
--- /dev/null
+++ b/libsemanage/include/semanage/ibendports_policy.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2017 Mellanox Techonologies Inc */
+
+#ifndef _SEMANAGE_IBENDPORTS_POLICY_H_
+#define _SEMANAGE_IBENDPORTS_POLICY_H_
+
+#include <semanage/handle.h>
+#include <semanage/ibendport_record.h>
+
+extern int semanage_ibendport_query(semanage_handle_t *handle,
+				    const semanage_ibendport_key_t *key,
+				    semanage_ibendport_t **response);
+
+extern int semanage_ibendport_exists(semanage_handle_t *handle,
+				     const semanage_ibendport_key_t *key, int *response);
+
+extern int semanage_ibendport_count(semanage_handle_t *handle,
+				    unsigned int *response);
+
+extern int semanage_ibendport_iterate(semanage_handle_t *handle,
+				      int (*handler)(const semanage_ibendport_t *record,
+						     void *varg),
+				      void *handler_arg);
+
+extern int semanage_ibendport_list(semanage_handle_t *handle,
+				   semanage_ibendport_t ***records,
+				   unsigned int *count);
+
+#endif
diff --git a/libsemanage/include/semanage/semanage.h b/libsemanage/include/semanage/semanage.h
index cebf3f44..04890148 100644
--- a/libsemanage/include/semanage/semanage.h
+++ b/libsemanage/include/semanage/semanage.h
@@ -34,6 +34,7 @@
 #include <semanage/iface_record.h>
 #include <semanage/port_record.h>
 #include <semanage/ibpkey_record.h>
+#include <semanage/ibendport_record.h>
 #include <semanage/node_record.h>
 
 /* Dbase */
@@ -49,6 +50,8 @@
 #include <semanage/ports_local.h>
 #include <semanage/ports_policy.h>
 #include <semanage/ibpkeys_local.h>
+#include <semanage/ibendports_local.h>
+#include <semanage/ibendports_policy.h>
 #include <semanage/ibpkeys_policy.h>
 #include <semanage/interfaces_local.h>
 #include <semanage/interfaces_policy.h>
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index 436e3340..68c18685 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -41,6 +41,7 @@
 #include "seuser_internal.h"
 #include "port_internal.h"
 #include "ibpkey_internal.h"
+#include "ibendport_internal.h"
 #include "iface_internal.h"
 #include "boolean_internal.h"
 #include "fcontext_internal.h"
@@ -226,11 +227,19 @@ int semanage_direct_connect(semanage_handle_t * sh)
 		goto err;
 
 	if (ibpkey_file_dbase_init(sh,
-				 semanage_path(SEMANAGE_ACTIVE,
-					       SEMANAGE_IBPKEYS_LOCAL),
-				 semanage_path(SEMANAGE_TMP,
-					       SEMANAGE_IBPKEYS_LOCAL),
-				 semanage_ibpkey_dbase_local(sh)) < 0)
+				   semanage_path(SEMANAGE_ACTIVE,
+						 SEMANAGE_IBPKEYS_LOCAL),
+				   semanage_path(SEMANAGE_TMP,
+						 SEMANAGE_IBPKEYS_LOCAL),
+				   semanage_ibpkey_dbase_local(sh)) < 0)
+		goto err;
+
+	if (ibendport_file_dbase_init(sh,
+				      semanage_path(SEMANAGE_ACTIVE,
+						    SEMANAGE_IBENDPORTS_LOCAL),
+				      semanage_path(SEMANAGE_TMP,
+						    SEMANAGE_IBENDPORTS_LOCAL),
+				      semanage_ibendport_dbase_local(sh)) < 0)
 		goto err;
 
 	/* Object databases: local modifications + policy */
@@ -260,6 +269,9 @@ int semanage_direct_connect(semanage_handle_t * sh)
 	if (ibpkey_policydb_dbase_init(sh, semanage_ibpkey_dbase_policy(sh)) < 0)
 		goto err;
 
+	if (ibendport_policydb_dbase_init(sh, semanage_ibendport_dbase_policy(sh)) < 0)
+		goto err;
+
 	if (iface_policydb_dbase_init(sh, semanage_iface_dbase_policy(sh)) < 0)
 		goto err;
 
@@ -333,6 +345,7 @@ static int semanage_direct_disconnect(semanage_handle_t * sh)
 	user_join_dbase_release(semanage_user_dbase_local(sh));
 	port_file_dbase_release(semanage_port_dbase_local(sh));
 	ibpkey_file_dbase_release(semanage_ibpkey_dbase_local(sh));
+	ibendport_file_dbase_release(semanage_ibendport_dbase_local(sh));
 	iface_file_dbase_release(semanage_iface_dbase_local(sh));
 	bool_file_dbase_release(semanage_bool_dbase_local(sh));
 	fcontext_file_dbase_release(semanage_fcontext_dbase_local(sh));
@@ -345,6 +358,7 @@ static int semanage_direct_disconnect(semanage_handle_t * sh)
 	user_join_dbase_release(semanage_user_dbase_policy(sh));
 	port_policydb_dbase_release(semanage_port_dbase_policy(sh));
 	ibpkey_policydb_dbase_release(semanage_ibpkey_dbase_policy(sh));
+	ibendport_policydb_dbase_release(semanage_ibendport_dbase_policy(sh));
 	iface_policydb_dbase_release(semanage_iface_dbase_policy(sh));
 	bool_policydb_dbase_release(semanage_bool_dbase_policy(sh));
 	fcontext_file_dbase_release(semanage_fcontext_dbase_policy(sh));
@@ -1158,7 +1172,8 @@ static int semanage_direct_commit(semanage_handle_t * sh)
 
 	int do_rebuild, do_write_kernel, do_install;
 	int fcontexts_modified, ports_modified, seusers_modified,
-		disable_dontaudit, preserve_tunables, ibpkeys_modified;
+		disable_dontaudit, preserve_tunables, ibpkeys_modified,
+		ibendports_modified;
 	dbase_config_t *users = semanage_user_dbase_local(sh);
 	dbase_config_t *users_base = semanage_user_base_dbase_local(sh);
 	dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh);
@@ -1167,6 +1182,8 @@ static int semanage_direct_commit(semanage_handle_t * sh)
 	dbase_config_t *pports = semanage_port_dbase_policy(sh);
 	dbase_config_t *ibpkeys = semanage_ibpkey_dbase_local(sh);
 	dbase_config_t *pibpkeys = semanage_ibpkey_dbase_policy(sh);
+	dbase_config_t *ibendports = semanage_ibendport_dbase_local(sh);
+	dbase_config_t *pibendports = semanage_ibendport_dbase_policy(sh);
 	dbase_config_t *bools = semanage_bool_dbase_local(sh);
 	dbase_config_t *pbools = semanage_bool_dbase_policy(sh);
 	dbase_config_t *ifaces = semanage_iface_dbase_local(sh);
@@ -1181,6 +1198,7 @@ static int semanage_direct_commit(semanage_handle_t * sh)
 	/* Modified flags that we need to use more than once. */
 	ports_modified = ports->dtable->is_modified(ports->dbase);
 	ibpkeys_modified = ibpkeys->dtable->is_modified(ibpkeys->dbase);
+	ibendports_modified = ibendports->dtable->is_modified(ibendports->dbase);
 	seusers_modified = seusers->dtable->is_modified(seusers->dbase);
 	fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
 
@@ -1303,6 +1321,7 @@ rebuild:
 	 * will be modified.
 	 */
 	do_write_kernel = do_rebuild | ports_modified | ibpkeys_modified |
+		ibendports_modified |
 		bools->dtable->is_modified(bools->dbase) |
 		ifaces->dtable->is_modified(ifaces->dbase) |
 		nodes->dtable->is_modified(nodes->dbase) |
@@ -1449,6 +1468,7 @@ rebuild:
 	dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pibpkeys->dbase, out);
+	dbase_policydb_attach((dbase_policydb_t *) pibendports->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
 	dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
@@ -1503,6 +1523,13 @@ rebuild:
 		if (retval < 0)
 			goto cleanup;
 	}
+
+	/* Validate local ibendports */
+	if (do_rebuild || ibendports_modified) {
+		retval = semanage_ibendport_validate_local(sh);
+		if (retval < 0)
+			goto cleanup;
+	}
 	/* ================== Write non-policydb components ========= */
 
 	/* Commit changes to components */
@@ -1583,6 +1610,7 @@ cleanup:
 	dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pibpkeys->dbase);
+	dbase_policydb_detach((dbase_policydb_t *) pibendports->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
 	dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
diff --git a/libsemanage/src/handle.h b/libsemanage/src/handle.h
index 306727a2..889871d8 100644
--- a/libsemanage/src/handle.h
+++ b/libsemanage/src/handle.h
@@ -79,7 +79,7 @@ struct semanage_handle {
 	struct semanage_policy_table *funcs;
 
 	/* Object databases */
-#define DBASE_COUNT      21
+#define DBASE_COUNT      23
 
 /* Local modifications */
 #define DBASE_LOCAL_USERS_BASE  0
@@ -92,21 +92,23 @@ struct semanage_handle {
 #define DBASE_LOCAL_SEUSERS     7
 #define DBASE_LOCAL_NODES       8
 #define DBASE_LOCAL_IBPKEYS     9
+#define DBASE_LOCAL_IBENDPORTS  10
 
 /* Policy + Local modifications */
-#define DBASE_POLICY_USERS_BASE  10
-#define DBASE_POLICY_USERS_EXTRA 11
-#define DBASE_POLICY_USERS       12
-#define DBASE_POLICY_PORTS       13
-#define DBASE_POLICY_INTERFACES  14
-#define DBASE_POLICY_BOOLEANS    15
-#define DBASE_POLICY_FCONTEXTS   16
-#define DBASE_POLICY_SEUSERS     17
-#define DBASE_POLICY_NODES       18
-#define DBASE_POLICY_IBPKEYS     19
+#define DBASE_POLICY_USERS_BASE  11
+#define DBASE_POLICY_USERS_EXTRA 12
+#define DBASE_POLICY_USERS       13
+#define DBASE_POLICY_PORTS       14
+#define DBASE_POLICY_INTERFACES  15
+#define DBASE_POLICY_BOOLEANS    16
+#define DBASE_POLICY_FCONTEXTS   17
+#define DBASE_POLICY_SEUSERS     18
+#define DBASE_POLICY_NODES       19
+#define DBASE_POLICY_IBPKEYS     20
+#define DBASE_POLICY_IBENDPORTS  21
 
 /* Active kernel policy */
-#define DBASE_ACTIVE_BOOLEANS    20
+#define DBASE_ACTIVE_BOOLEANS    22
 	dbase_config_t dbase[DBASE_COUNT];
 };
 
@@ -142,6 +144,12 @@ static inline
 }
 
 static inline
+    dbase_config_t * semanage_ibendport_dbase_local(semanage_handle_t * handle)
+{
+	return &handle->dbase[DBASE_LOCAL_IBENDPORTS];
+}
+
+static inline
     dbase_config_t * semanage_iface_dbase_local(semanage_handle_t * handle)
 {
 	return &handle->dbase[DBASE_LOCAL_INTERFACES];
@@ -204,6 +212,12 @@ static inline
 }
 
 static inline
+    dbase_config_t * semanage_ibendport_dbase_policy(semanage_handle_t * handle)
+{
+	return &handle->dbase[DBASE_POLICY_IBENDPORTS];
+}
+
+static inline
     dbase_config_t * semanage_iface_dbase_policy(semanage_handle_t * handle)
 {
 	return &handle->dbase[DBASE_POLICY_INTERFACES];
diff --git a/libsemanage/src/ibendport_internal.h b/libsemanage/src/ibendport_internal.h
new file mode 100644
index 00000000..970fbdb2
--- /dev/null
+++ b/libsemanage/src/ibendport_internal.h
@@ -0,0 +1,48 @@
+#ifndef _SEMANAGE_IBENDPORT_INTERNAL_H_
+#define _SEMANAGE_IBENDPORT_INTERNAL_H_
+
+#include <semanage/ibendport_record.h>
+#include <semanage/ibendports_local.h>
+#include <semanage/ibendports_policy.h>
+#include "database.h"
+#include "handle.h"
+#include "dso.h"
+
+hidden_proto(semanage_ibendport_create)
+hidden_proto(semanage_ibendport_compare)
+hidden_proto(semanage_ibendport_compare2)
+hidden_proto(semanage_ibendport_clone)
+hidden_proto(semanage_ibendport_free)
+hidden_proto(semanage_ibendport_key_extract)
+hidden_proto(semanage_ibendport_key_free)
+hidden_proto(semanage_ibendport_get_port)
+hidden_proto(semanage_ibendport_set_port)
+hidden_proto(semanage_ibendport_get_con)
+hidden_proto(semanage_ibendport_set_con)
+hidden_proto(semanage_ibendport_list_local)
+hidden_proto(semanage_ibendport_get_ibdev_name)
+hidden_proto(semanage_ibendport_set_ibdev_name)
+
+/* IBENDPORT RECORD: method table */
+extern record_table_t SEMANAGE_IBENDPORT_RTABLE;
+
+extern int ibendport_file_dbase_init(semanage_handle_t *handle,
+				     const char *path_ro,
+				     const char *path_rw,
+				     dbase_config_t *dconfig);
+
+extern void ibendport_file_dbase_release(dbase_config_t *dconfig);
+
+extern int ibendport_policydb_dbase_init(semanage_handle_t *handle,
+					 dbase_config_t *dconfig);
+
+extern void ibendport_policydb_dbase_release(dbase_config_t *dconfig);
+
+extern int hidden semanage_ibendport_validate_local(semanage_handle_t *handle);
+
+/* ==== Internal (to ibendports) API === */
+
+hidden int semanage_ibendport_compare2_qsort(const semanage_ibendport_t **ibendport,
+					     const semanage_ibendport_t **ibendport2);
+
+#endif
diff --git a/libsemanage/src/ibendport_record.c b/libsemanage/src/ibendport_record.c
new file mode 100644
index 00000000..955067ea
--- /dev/null
+++ b/libsemanage/src/ibendport_record.c
@@ -0,0 +1,154 @@
+/*Copyright (C) 2005 Red Hat, Inc. */
+
+/*Object: semanage_ibendport_t (Infiniband Pkey)
+ *Object: semanage_ibendport_key_t (Infiniband Pkey Key)
+ *Implements: record_t (Database Record)
+ *Implements: record_key_t (Database Record Key)
+ */
+
+#include <sepol/context_record.h>
+#include <sepol/ibendport_record.h>
+
+typedef sepol_context_t semanage_context_t;
+typedef sepol_ibendport_t semanage_ibendport_t;
+typedef sepol_ibendport_key_t semanage_ibendport_key_t;
+#define _SEMANAGE_IBENDPORT_DEFINED_
+#define _SEMANAGE_CONTEXT_DEFINED_
+
+typedef semanage_ibendport_t record_t;
+typedef semanage_ibendport_key_t record_key_t;
+#define DBASE_RECORD_DEFINED
+
+#include "ibendport_internal.h"
+#include "handle.h"
+#include "database.h"
+
+int semanage_ibendport_compare(const semanage_ibendport_t *ibendport,
+			       const semanage_ibendport_key_t *key)
+{
+	return sepol_ibendport_compare(ibendport, key);
+}
+
+hidden_def(semanage_ibendport_compare)
+
+int semanage_ibendport_compare2(const semanage_ibendport_t *ibendport,
+				const semanage_ibendport_t *ibendport2)
+{
+	return sepol_ibendport_compare2(ibendport, ibendport2);
+}
+
+hidden_def(semanage_ibendport_compare2)
+
+hidden int semanage_ibendport_compare2_qsort(const semanage_ibendport_t **ibendport,
+					     const semanage_ibendport_t **ibendport2)
+{
+	return sepol_ibendport_compare2(*ibendport, *ibendport2);
+}
+
+int semanage_ibendport_key_create(semanage_handle_t *handle,
+				  const char *ibdev_name,
+				  int port,
+				  semanage_ibendport_key_t **key_ptr)
+{
+	return sepol_ibendport_key_create(handle->sepolh, ibdev_name, port, key_ptr);
+}
+
+int semanage_ibendport_key_extract(semanage_handle_t *handle,
+				   const semanage_ibendport_t *ibendport,
+				   semanage_ibendport_key_t **key_ptr)
+{
+	return sepol_ibendport_key_extract(handle->sepolh, ibendport, key_ptr);
+}
+
+hidden_def(semanage_ibendport_key_extract)
+
+void semanage_ibendport_key_free(semanage_ibendport_key_t *key)
+{
+	sepol_ibendport_key_free(key);
+}
+
+hidden_def(semanage_ibendport_key_free)
+
+int semanage_ibendport_get_ibdev_name(semanage_handle_t *handle,
+				      const semanage_ibendport_t *ibendport,
+				      char **ibdev_name_ptr)
+{
+	return sepol_ibendport_get_ibdev_name(handle->sepolh, ibendport, ibdev_name_ptr);
+}
+
+hidden_def(semanage_ibendport_get_ibdev_name)
+
+int semanage_ibendport_set_ibdev_name(semanage_handle_t *handle,
+				      semanage_ibendport_t *ibendport,
+				      const char *ibdev_name)
+{
+	return sepol_ibendport_set_ibdev_name(handle->sepolh, ibendport, ibdev_name);
+}
+
+hidden_def(semanage_ibendport_set_ibdev_name)
+
+int semanage_ibendport_get_port(const semanage_ibendport_t *ibendport)
+{
+	return sepol_ibendport_get_port(ibendport);
+}
+
+hidden_def(semanage_ibendport_get_port)
+
+void semanage_ibendport_set_port(semanage_ibendport_t *ibendport, int port)
+{
+	sepol_ibendport_set_port(ibendport, port);
+}
+
+hidden_def(semanage_ibendport_set_port)
+
+semanage_context_t *semanage_ibendport_get_con(const semanage_ibendport_t *ibendport)
+{
+	return sepol_ibendport_get_con(ibendport);
+}
+
+hidden_def(semanage_ibendport_get_con)
+
+int semanage_ibendport_set_con(semanage_handle_t *handle,
+			       semanage_ibendport_t *ibendport,
+			       semanage_context_t *con)
+{
+	return sepol_ibendport_set_con(handle->sepolh, ibendport, con);
+}
+
+hidden_def(semanage_ibendport_set_con)
+
+int semanage_ibendport_create(semanage_handle_t *handle,
+			      semanage_ibendport_t **ibendport_ptr)
+{
+	return sepol_ibendport_create(handle->sepolh, ibendport_ptr);
+}
+
+hidden_def(semanage_ibendport_create)
+
+int semanage_ibendport_clone(semanage_handle_t *handle,
+			     const semanage_ibendport_t *ibendport,
+			     semanage_ibendport_t **ibendport_ptr)
+{
+	return sepol_ibendport_clone(handle->sepolh, ibendport, ibendport_ptr);
+}
+
+hidden_def(semanage_ibendport_clone)
+
+void semanage_ibendport_free(semanage_ibendport_t *ibendport)
+{
+	sepol_ibendport_free(ibendport);
+}
+
+hidden_def(semanage_ibendport_free)
+
+/*key base functions */
+record_table_t SEMANAGE_IBENDPORT_RTABLE = {
+	.create = semanage_ibendport_create,
+	.key_extract = semanage_ibendport_key_extract,
+	.key_free = semanage_ibendport_key_free,
+	.clone = semanage_ibendport_clone,
+	.compare = semanage_ibendport_compare,
+	.compare2 = semanage_ibendport_compare2,
+	.compare2_qsort = semanage_ibendport_compare2_qsort,
+	.free = semanage_ibendport_free,
+};
diff --git a/libsemanage/src/ibendports_file.c b/libsemanage/src/ibendports_file.c
new file mode 100644
index 00000000..402c7a5e
--- /dev/null
+++ b/libsemanage/src/ibendports_file.c
@@ -0,0 +1,157 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc. */
+
+struct semanage_ibendport;
+struct semanage_ibendport_key;
+typedef struct semanage_ibendport record_t;
+typedef struct semanage_ibendport_key record_key_t;
+#define DBASE_RECORD_DEFINED
+
+struct dbase_file;
+typedef struct dbase_file dbase_t;
+#define DBASE_DEFINED
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <semanage/handle.h>
+#include "ibendport_internal.h"
+#include "context_internal.h"
+#include "database_file.h"
+#include "parse_utils.h"
+#include "debug.h"
+
+static int ibendport_print(semanage_handle_t *handle,
+			   semanage_ibendport_t *ibendport,
+			   FILE *str)
+{
+	char *con_str = NULL;
+	char *ibdev_name_str = NULL;
+	int port = semanage_ibendport_get_port(ibendport);
+
+	if (semanage_ibendport_get_ibdev_name(handle, ibendport, &ibdev_name_str) != 0)
+		goto err;
+
+	semanage_context_t *con = semanage_ibendport_get_con(ibendport);
+
+	if (fprintf(str, "ibendportcon %s ", ibdev_name_str) < 0)
+		goto err;
+
+	if (fprintf(str, "%d ", port) < 0)
+		goto err;
+
+	if (semanage_context_to_string(handle, con, &con_str) < 0)
+		goto err;
+	if (fprintf(str, "%s\n", con_str) < 0)
+		goto err;
+
+	free(ibdev_name_str);
+	free(con_str);
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not print ibendport (%s) %u to stream",
+	    ibdev_name_str, port);
+	free(ibdev_name_str);
+	free(con_str);
+	return STATUS_ERR;
+}
+
+static int ibendport_parse(semanage_handle_t *handle,
+			   parse_info_t *info,
+			   semanage_ibendport_t *ibendport)
+{
+	int port;
+	char *str = NULL;
+	semanage_context_t *con = NULL;
+
+	if (parse_skip_space(handle, info) < 0)
+		goto err;
+	if (!info->ptr)
+		goto last;
+
+	/* Header */
+	if (parse_assert_str(handle, info, "ibendportcon") < 0)
+		goto err;
+	if (parse_assert_space(handle, info) < 0)
+		goto err;
+
+	/* IB Device Name */
+	if (parse_fetch_string(handle, info, &str, ' ') < 0)
+		goto err;
+	if (semanage_ibendport_set_ibdev_name(handle, ibendport, str) < 0)
+		goto err;
+	free(str);
+	str = NULL;
+
+	/* Port */
+	if (parse_assert_space(handle, info) < 0)
+		goto err;
+	if (parse_fetch_int(handle, info, &port, ' ') < 0)
+		goto err;
+	semanage_ibendport_set_port(ibendport, port);
+
+	/* context */
+	if (parse_assert_space(handle, info) < 0)
+		goto err;
+	if (parse_fetch_string(handle, info, &str, ' ') < 0)
+		goto err;
+	if (semanage_context_from_string(handle, str, &con) < 0) {
+		ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
+		    str, info->filename, info->lineno, info->orig_line);
+		goto err;
+	}
+	if (!con) {
+		ERR(handle, "<<none>> context is not valid for ibendport (%s: %u):\n%s",
+		    info->filename, info->lineno, info->orig_line);
+		goto err;
+	}
+	free(str);
+	str = NULL;
+
+	if (semanage_ibendport_set_con(handle, ibendport, con) < 0)
+		goto err;
+
+	if (parse_assert_space(handle, info) < 0)
+		goto err;
+
+	semanage_context_free(con);
+	return STATUS_SUCCESS;
+
+last:
+	parse_dispose_line(info);
+	return STATUS_NODATA;
+
+err:
+	ERR(handle, "could not parse ibendport record");
+	free(str);
+	semanage_context_free(con);
+	parse_dispose_line(info);
+	return STATUS_ERR;
+}
+
+/* IBENDPORT RECORD: FILE extension: method table */
+record_file_table_t SEMANAGE_IBENDPORT_FILE_RTABLE = {
+	.parse = ibendport_parse,
+	.print = ibendport_print,
+};
+
+int ibendport_file_dbase_init(semanage_handle_t *handle,
+			      const char *path_ro,
+			      const char *path_rw,
+			      dbase_config_t *dconfig)
+{
+	if (dbase_file_init(handle,
+			    path_ro,
+			    path_rw,
+			    &SEMANAGE_IBENDPORT_RTABLE,
+			    &SEMANAGE_IBENDPORT_FILE_RTABLE, &dconfig->dbase) < 0)
+		return STATUS_ERR;
+
+	dconfig->dtable = &SEMANAGE_FILE_DTABLE;
+	return STATUS_SUCCESS;
+}
+
+void ibendport_file_dbase_release(dbase_config_t *dconfig)
+{
+	dbase_file_release(dconfig->dbase);
+}
diff --git a/libsemanage/src/ibendports_local.c b/libsemanage/src/ibendports_local.c
new file mode 100644
index 00000000..8b5567d8
--- /dev/null
+++ b/libsemanage/src/ibendports_local.c
@@ -0,0 +1,153 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc */
+
+struct semanage_ibendport;
+struct semanage_ibendport_key;
+typedef struct semanage_ibendport_key record_key_t;
+typedef struct semanage_ibendport record_t;
+#define DBASE_RECORD_DEFINED
+
+#include <stdlib.h>
+#include <string.h>
+#include <sepol/policydb.h>
+#include "ibendport_internal.h"
+#include "debug.h"
+#include "handle.h"
+#include "database.h"
+
+int semanage_ibendport_modify_local(semanage_handle_t *handle,
+				    const semanage_ibendport_key_t *key,
+				    const semanage_ibendport_t *data)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle);
+
+	return dbase_modify(handle, dconfig, key, data);
+}
+
+int semanage_ibendport_del_local(semanage_handle_t *handle,
+				 const semanage_ibendport_key_t *key)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle);
+
+	return dbase_del(handle, dconfig, key);
+}
+
+int semanage_ibendport_query_local(semanage_handle_t *handle,
+				   const semanage_ibendport_key_t *key,
+				   semanage_ibendport_t **response)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle);
+
+	return dbase_query(handle, dconfig, key, response);
+}
+
+int semanage_ibendport_exists_local(semanage_handle_t *handle,
+				    const semanage_ibendport_key_t *key,
+				    int *response)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle);
+
+	return dbase_exists(handle, dconfig, key, response);
+}
+
+int semanage_ibendport_count_local(semanage_handle_t *handle,
+				   unsigned int *response)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle);
+
+	return dbase_count(handle, dconfig, response);
+}
+
+int semanage_ibendport_iterate_local(semanage_handle_t *handle,
+				     int (*handler)(const semanage_ibendport_t *record,
+						    void *varg), void *handler_arg)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle);
+	return dbase_iterate(handle, dconfig, handler, handler_arg);
+}
+
+int semanage_ibendport_list_local(semanage_handle_t *handle,
+				  semanage_ibendport_t ***records,
+				  unsigned int *count)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_local(handle);
+
+	return dbase_list(handle, dconfig, records, count);
+}
+
+hidden_def(semanage_ibendport_list_local)
+
+int hidden semanage_ibendport_validate_local(semanage_handle_t *handle)
+{
+	semanage_ibendport_t **ibendports = NULL;
+	unsigned int nibendports = 0;
+	unsigned int i = 0, j = 0;
+	char *ibdev_name;
+	char *ibdev_name2;
+	int port;
+	int port2;
+
+	/* List and sort the ibendports */
+	if (semanage_ibendport_list_local(handle, &ibendports, &nibendports) < 0)
+		goto err;
+
+	qsort(ibendports, nibendports, sizeof(semanage_ibendport_t *),
+	      (int (*)(const void *, const void *))
+	      &semanage_ibendport_compare2_qsort);
+
+	/* Test each ibendport */
+	while (i < nibendports) {
+		int stop = 0;
+
+		if (STATUS_SUCCESS !=
+				semanage_ibendport_get_ibdev_name(handle,
+								  ibendports[i],
+								  &ibdev_name)) {
+			ERR(handle, "Couldn't get IB device name");
+			goto err;
+		}
+
+		port = semanage_ibendport_get_port(ibendports[i]);
+
+		/* Find the first ibendport with matching
+		 * ibdev_name to compare against
+		 */
+		do {
+			if (j == nibendports - 1)
+				goto next;
+			j++;
+			if (STATUS_SUCCESS !=
+				semanage_ibendport_get_ibdev_name(handle,
+								  ibendports[j],
+								  &ibdev_name2)) {
+				ERR(handle, "Couldn't get IB device name.");
+				goto err;
+			}
+			port2 = semanage_ibendport_get_port(ibendports[j]);
+
+			stop = !strcmp(ibdev_name, ibdev_name2);
+		} while (!stop);
+
+		if (port == port2) {
+			ERR(handle, "ibendport %s/%u already exists.",
+			    ibdev_name2, port2);
+			goto invalid;
+		}
+next:
+		i++;
+		j = i;
+	}
+
+	for (i = 0; i < nibendports; i++)
+		semanage_ibendport_free(ibendports[i]);
+	free(ibendports);
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not complete ibendports validity check");
+
+invalid:
+	for (i = 0; i < nibendports; i++)
+		semanage_ibendport_free(ibendports[i]);
+	free(ibendports);
+	return STATUS_ERR;
+}
diff --git a/libsemanage/src/ibendports_policy.c b/libsemanage/src/ibendports_policy.c
new file mode 100644
index 00000000..1347b67c
--- /dev/null
+++ b/libsemanage/src/ibendports_policy.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 2017 Mellanox Technologies Inc */
+
+struct semanage_ibendport;
+struct semanage_ibendport_key;
+typedef struct semanage_ibendport_key record_key_t;
+typedef struct semanage_ibendport record_t;
+#define DBASE_RECORD_DEFINED
+
+#include "ibendport_internal.h"
+#include "handle.h"
+#include "database.h"
+
+int semanage_ibendport_query(semanage_handle_t *handle,
+			     const semanage_ibendport_key_t *key,
+			     semanage_ibendport_t **response)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle);
+
+	return dbase_query(handle, dconfig, key, response);
+}
+
+int semanage_ibendport_exists(semanage_handle_t *handle,
+			      const semanage_ibendport_key_t *key,
+			      int *response)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle);
+
+	return dbase_exists(handle, dconfig, key, response);
+}
+
+int semanage_ibendport_count(semanage_handle_t *handle,
+			     unsigned int *response)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle);
+
+	return dbase_count(handle, dconfig, response);
+}
+
+int semanage_ibendport_iterate(semanage_handle_t *handle,
+			       int (*handler)(const semanage_ibendport_t *record,
+					      void *varg), void *handler_arg)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle);
+
+	return dbase_iterate(handle, dconfig, handler, handler_arg);
+}
+
+int semanage_ibendport_list(semanage_handle_t *handle,
+			    semanage_ibendport_t ***records,
+			    unsigned int *count)
+{
+	dbase_config_t *dconfig = semanage_ibendport_dbase_policy(handle);
+
+	return dbase_list(handle, dconfig, records, count);
+}
diff --git a/libsemanage/src/ibendports_policydb.c b/libsemanage/src/ibendports_policydb.c
new file mode 100644
index 00000000..1029810e
--- /dev/null
+++ b/libsemanage/src/ibendports_policydb.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 Mellanox Technologies Inc
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ */
+
+struct semanage_ibendport;
+struct semanage_ibendport_key;
+typedef struct semanage_ibendport record_t;
+typedef struct semanage_ibendport_key record_key_t;
+#define DBASE_RECORD_DEFINED
+
+struct dbase_policydb;
+typedef struct dbase_policydb dbase_t;
+#define DBASE_DEFINED
+
+#include <sepol/ibendports.h>
+#include <semanage/handle.h>
+#include "ibendport_internal.h"
+#include "debug.h"
+#include "database_policydb.h"
+#include "semanage_store.h"
+
+/* IBENDPORT RECORD (SEPOL): POLICYDB extension : method table */
+record_policydb_table_t SEMANAGE_IBENDPORT_POLICYDB_RTABLE = {
+	.add = NULL,
+	.modify = (record_policydb_table_modify_t)sepol_ibendport_modify,
+	.set = NULL,
+	.query = (record_policydb_table_query_t)sepol_ibendport_query,
+	.count = (record_policydb_table_count_t)sepol_ibendport_count,
+	.exists = (record_policydb_table_exists_t)sepol_ibendport_exists,
+	.iterate = (record_policydb_table_iterate_t)sepol_ibendport_iterate,
+};
+
+int ibendport_policydb_dbase_init(semanage_handle_t *handle,
+				  dbase_config_t *dconfig)
+{
+	if (dbase_policydb_init(handle,
+				semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL),
+				semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
+				&SEMANAGE_IBENDPORT_RTABLE,
+				&SEMANAGE_IBENDPORT_POLICYDB_RTABLE,
+				&dconfig->dbase) < 0)
+		return STATUS_ERR;
+
+	dconfig->dtable = &SEMANAGE_POLICYDB_DTABLE;
+
+	return STATUS_SUCCESS;
+}
+
+void ibendport_policydb_dbase_release(dbase_config_t *dconfig)
+{
+	dbase_policydb_release(dconfig->dbase);
+}
diff --git a/libsemanage/src/libsemanage.map b/libsemanage/src/libsemanage.map
index 041b1ce1..02036696 100644
--- a/libsemanage/src/libsemanage.map
+++ b/libsemanage/src/libsemanage.map
@@ -19,6 +19,7 @@ LIBSEMANAGE_1.0 {
 	  semanage_user_*; semanage_bool_*; semanage_seuser_*;
 	  semanage_iface_*; semanage_port_*; semanage_context_*;
 	  semanage_ibpkey_*;
+	  semanage_ibendport_*;
 	  semanage_node_*;
 	  semanage_fcontext_*; semanage_access_check; semanage_set_create_store;
 	  semanage_is_connected; semanage_get_disable_dontaudit; semanage_set_disable_dontaudit;
diff --git a/libsemanage/src/policy_components.c b/libsemanage/src/policy_components.c
index 136c5a76..896ac512 100644
--- a/libsemanage/src/policy_components.c
+++ b/libsemanage/src/policy_components.c
@@ -140,6 +140,9 @@ int semanage_base_merge_components(semanage_handle_t * handle)
 
 		{semanage_ibpkey_dbase_local(handle),
 		 semanage_ibpkey_dbase_policy(handle), MODE_MODIFY},
+
+		{semanage_ibendport_dbase_local(handle),
+		 semanage_ibendport_dbase_policy(handle), MODE_MODIFY},
 	};
 	const unsigned int CCOUNT = sizeof(components) / sizeof(components[0]);
 
@@ -221,6 +224,7 @@ int semanage_commit_components(semanage_handle_t * handle)
 		semanage_bool_dbase_active(handle),
 		semanage_node_dbase_local(handle),
 		semanage_ibpkey_dbase_local(handle),
+		semanage_ibendport_dbase_local(handle),
 	};
 	const int CCOUNT = sizeof(components) / sizeof(components[0]);
 
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index f61f3b2e..56427721 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -100,6 +100,7 @@ static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
 	"/file_contexts.template",
 	"/commit_num",
 	"/pkeys.local",
+	"/ibendports.local",
 	"/ports.local",
 	"/interfaces.local",
 	"/nodes.local",
diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h
index c7bcf443..fcaa505f 100644
--- a/libsemanage/src/semanage_store.h
+++ b/libsemanage/src/semanage_store.h
@@ -45,6 +45,7 @@ enum semanage_sandbox_defs {
 	SEMANAGE_FC_TMPL,
 	SEMANAGE_COMMIT_NUM_FILE,
 	SEMANAGE_IBPKEYS_LOCAL,
+	SEMANAGE_IBENDPORTS_LOCAL,
 	SEMANAGE_PORTS_LOCAL,
 	SEMANAGE_INTERFACES_LOCAL,
 	SEMANAGE_NODES_LOCAL,
diff --git a/libsemanage/src/semanageswig.i b/libsemanage/src/semanageswig.i
index d3ca7959..ebf39cfb 100644
--- a/libsemanage/src/semanageswig.i
+++ b/libsemanage/src/semanageswig.i
@@ -42,6 +42,9 @@
 %include "../include/semanage/ibpkey_record.h"
 %include "../include/semanage/ibpkeys_local.h"
 %include "../include/semanage/ibpkeys_policy.h"
+%include "../include/semanage/ibendport_record.h"
+%include "../include/semanage/ibendports_local.h"
+%include "../include/semanage/ibendports_policy.h"
 %include "../include/semanage/fcontext_record.h"
 %include "../include/semanage/fcontexts_local.h"
 %include "../include/semanage/fcontexts_policy.h"
diff --git a/libsemanage/src/semanageswig_python.i b/libsemanage/src/semanageswig_python.i
index 40932d8c..8604b8aa 100644
--- a/libsemanage/src/semanageswig_python.i
+++ b/libsemanage/src/semanageswig_python.i
@@ -480,6 +480,49 @@
 	$1 = &temp;
 }
 
+/** ibendport typemaps **/
+
+/* the wrapper will setup this parameter for passing... the resulting python functions
+   will not take the semanage_ibendport_t *** parameter */
+%typemap(in, numinputs=0) semanage_ibendport_t ***(semanage_ibendport_t **temp=NULL) {
+	$1 = &temp;
+}
+
+%typemap(argout) (
+	semanage_handle_t* handle,
+	semanage_ibendport_t*** records,
+	unsigned int* count) {
+
+	if ($result) {
+		int value;
+		SWIG_AsVal_int($result, &value);
+		if (value >= 0) {
+			PyObject* plist = NULL;
+			if (semanage_array2plist($1, (void**) *$2, *$3, SWIGTYPE_p_semanage_ibendport,
+				(void (*) (void*)) &semanage_ibendport_free, &plist) < 0)
+				$result = SWIG_From_int(STATUS_ERR);
+			else
+				$result = SWIG_Python_AppendOutput($result, plist);
+		}
+	}
+}
+
+%typemap(in, numinputs=0) semanage_ibendport_t **(semanage_ibendport_t *temp=NULL) {
+	$1 = &temp;
+}
+
+%typemap(argout) semanage_ibendport_t ** {
+	$result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
+}
+
+%typemap(argout) semanage_ibendport_key_t ** {
+	$result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj(*$1, $*1_descriptor, 0));
+}
+
+%typemap(in, numinputs=0) semanage_ibendport_key_t **(semanage_ibendport_key_t *temp=NULL) {
+	$1 = &temp;
+}
+
 /** node typemaps **/
 
 /* the wrapper will setup this parameter for passing... the resulting python functions
diff --git a/libsemanage/utils/semanage_migrate_store b/libsemanage/utils/semanage_migrate_store
index 325de47d..9a9fac22 100755
--- a/libsemanage/utils/semanage_migrate_store
+++ b/libsemanage/utils/semanage_migrate_store
@@ -254,7 +254,8 @@ if __name__ == "__main__":
 		"policy.kern",
 		"file_contexts",
 		"homedir_template",
-                "pkeys.local"]
+                "pkeys.local",
+                "ibendports.local"]
 
 
 	create_dir(newroot_path(), 0o755)
diff --git a/libsepol/include/sepol/ibendport_record.h b/libsepol/include/sepol/ibendport_record.h
new file mode 100644
index 00000000..e30b252d
--- /dev/null
+++ b/libsepol/include/sepol/ibendport_record.h
@@ -0,0 +1,68 @@
+#ifndef _SEPOL_IBENDPORT_RECORD_H_
+#define _SEPOL_IBENDPORT_RECORD_H_
+
+#include <stddef.h>
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct sepol_ibendport;
+struct sepol_ibendport_key;
+typedef struct sepol_ibendport sepol_ibendport_t;
+typedef struct sepol_ibendport_key sepol_ibendport_key_t;
+
+extern int sepol_ibendport_compare(const sepol_ibendport_t *ibendport,
+				   const sepol_ibendport_key_t *key);
+
+extern int sepol_ibendport_compare2(const sepol_ibendport_t *ibendport,
+				    const sepol_ibendport_t *ibendport2);
+
+extern int sepol_ibendport_key_create(sepol_handle_t *handle,
+				      const char *ibdev_name,
+				      int port,
+				      sepol_ibendport_key_t **key_ptr);
+
+extern void sepol_ibendport_key_unpack(const sepol_ibendport_key_t *key,
+				       const char **ibdev_name,
+				       int *port);
+
+extern int sepol_ibendport_alloc_ibdev_name(sepol_handle_t *handle,
+					    char **ibdev_name);
+
+extern int sepol_ibendport_key_extract(sepol_handle_t *handle,
+				       const sepol_ibendport_t *ibendport,
+				       sepol_ibendport_key_t **key_ptr);
+
+extern void sepol_ibendport_key_free(sepol_ibendport_key_t *key);
+
+extern void sepol_ibendport_set_port(sepol_ibendport_t *ibendport, int port);
+
+extern int sepol_ibendport_get_port(const sepol_ibendport_t *ibendport);
+
+extern int sepol_ibendport_get_ibdev_name(sepol_handle_t *handle,
+					  const sepol_ibendport_t *ibendport,
+					  char **ibdev_name);
+
+extern int sepol_ibendport_set_ibdev_name(sepol_handle_t *handle,
+					  sepol_ibendport_t *ibendport,
+					  const char *ibdev_name);
+
+extern sepol_context_t *sepol_ibendport_get_con(const sepol_ibendport_t *ibendport);
+
+extern int sepol_ibendport_set_con(sepol_handle_t *handle,
+				   sepol_ibendport_t *ibendport,
+				   sepol_context_t *con);
+
+extern int sepol_ibendport_create(sepol_handle_t *handle,
+				  sepol_ibendport_t **ibendport_ptr);
+
+extern int sepol_ibendport_clone(sepol_handle_t *handle,
+				 const sepol_ibendport_t *ibendport,
+				 sepol_ibendport_t **ibendport_ptr);
+
+extern void sepol_ibendport_free(sepol_ibendport_t *ibendport);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/ibendports.h b/libsepol/include/sepol/ibendports.h
new file mode 100644
index 00000000..4a89e0ca
--- /dev/null
+++ b/libsepol/include/sepol/ibendports.h
@@ -0,0 +1,45 @@
+#ifndef _SEPOL_IBENDPORTS_H_
+#define _SEPOL_IBENDPORTS_H_
+
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/ibendport_record.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Return the number of ibendports */
+extern int sepol_ibendport_count(sepol_handle_t *handle,
+				 const sepol_policydb_t *p,
+				 unsigned int *response);
+
+/* Check if a ibendport exists */
+extern int sepol_ibendport_exists(sepol_handle_t *handle,
+				  const sepol_policydb_t *policydb,
+				  const sepol_ibendport_key_t *key, int *response);
+
+/* Query a ibendport - returns the ibendport, or NULL if not found */
+extern int sepol_ibendport_query(sepol_handle_t *handle,
+				 const sepol_policydb_t *policydb,
+				 const sepol_ibendport_key_t *key,
+				 sepol_ibendport_t **response);
+
+/* Modify a ibendport, or add it, if the key is not found */
+extern int sepol_ibendport_modify(sepol_handle_t *handle,
+				  sepol_policydb_t *policydb,
+				  const sepol_ibendport_key_t *key,
+				  const sepol_ibendport_t *data);
+
+/* Iterate the ibendports
+ * The handler may return:
+ * -1 to signal an error condition,
+ * 1 to signal successful exit
+ * 0 to signal continue
+ */
+extern int sepol_ibendport_iterate(sepol_handle_t *handle,
+				   const sepol_policydb_t *policydb,
+				   int (*fn)(const sepol_ibendport_t *ibendport,
+					     void *fn_arg), void *arg);
+
+__END_DECLS
+#endif
diff --git a/libsepol/include/sepol/sepol.h b/libsepol/include/sepol/sepol.h
index 540f01dc..540609a1 100644
--- a/libsepol/include/sepol/sepol.h
+++ b/libsepol/include/sepol/sepol.h
@@ -12,6 +12,7 @@ extern "C" {
 #include <sepol/context_record.h>
 #include <sepol/iface_record.h>
 #include <sepol/ibpkey_record.h>
+#include <sepol/ibendport_record.h>
 #include <sepol/port_record.h>
 #include <sepol/boolean_record.h>
 #include <sepol/node_record.h>
@@ -19,6 +20,7 @@ extern "C" {
 #include <sepol/booleans.h>
 #include <sepol/interfaces.h>
 #include <sepol/ibpkeys.h>
+#include <sepol/ibendports.h>
 #include <sepol/ports.h>
 #include <sepol/nodes.h>
 #include <sepol/users.h>
diff --git a/libsepol/src/ibendport_internal.h b/libsepol/src/ibendport_internal.h
new file mode 100644
index 00000000..ed8f9b4d
--- /dev/null
+++ b/libsepol/src/ibendport_internal.h
@@ -0,0 +1,18 @@
+#ifndef _SEPOL_IBENDPORT_INTERNAL_H_
+#define _SEPOL_IBENDPORT_INTERNAL_H_
+
+#include <sepol/ibendport_record.h>
+#include <sepol/ibendports.h>
+#include "dso.h"
+
+hidden_proto(sepol_ibendport_create)
+hidden_proto(sepol_ibendport_free)
+hidden_proto(sepol_ibendport_get_con)
+hidden_proto(sepol_ibendport_get_port)
+hidden_proto(sepol_ibendport_key_create)
+hidden_proto(sepol_ibendport_key_unpack)
+hidden_proto(sepol_ibendport_set_con)
+hidden_proto(sepol_ibendport_set_port)
+hidden_proto(sepol_ibendport_get_ibdev_name)
+hidden_proto(sepol_ibendport_set_ibdev_name)
+#endif
diff --git a/libsepol/src/ibendport_record.c b/libsepol/src/ibendport_record.c
new file mode 100644
index 00000000..912aeb53
--- /dev/null
+++ b/libsepol/src/ibendport_record.c
@@ -0,0 +1,298 @@
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "sepol/policydb/policydb.h"
+#include "ibendport_internal.h"
+#include "context_internal.h"
+#include "debug.h"
+
+struct sepol_ibendport {
+	/* Device Name */
+	char *ibdev_name;
+
+	/* Port number */
+	int port;
+
+	/* Context */
+	sepol_context_t *con;
+};
+
+struct sepol_ibendport_key {
+	/* Device Name */
+	char *ibdev_name;
+
+	/* Port number */
+	int port;
+};
+
+/* Allocates a sufficiently large string (ibdev_name) */
+int sepol_ibendport_alloc_ibdev_name(sepol_handle_t *handle,
+				     char **ibdev_name)
+{
+	char *tmp_ibdev_name = NULL;
+
+	tmp_ibdev_name = calloc(1, IB_DEVICE_NAME_MAX);
+
+	if (!tmp_ibdev_name)
+		goto omem;
+
+	*ibdev_name = tmp_ibdev_name;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+	ERR(handle, "could not allocate string buffer for ibdev_name");
+	return STATUS_ERR;
+}
+
+/* Key */
+int sepol_ibendport_key_create(sepol_handle_t *handle,
+			       const char *ibdev_name,
+			       int port,
+			       sepol_ibendport_key_t **key_ptr)
+{
+	sepol_ibendport_key_t *tmp_key =
+	    (sepol_ibendport_key_t *)malloc(sizeof(sepol_ibendport_key_t));
+
+	if (!tmp_key) {
+		ERR(handle, "out of memory, could not create ibendport key");
+		goto omem;
+	}
+
+	if (sepol_ibendport_alloc_ibdev_name(handle, &tmp_key->ibdev_name) < 0)
+		goto err;
+
+	strncpy(tmp_key->ibdev_name, ibdev_name, IB_DEVICE_NAME_MAX);
+	tmp_key->port = port;
+
+	*key_ptr = tmp_key;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+
+err:
+	sepol_ibendport_key_free(tmp_key);
+	ERR(handle, "could not create ibendport key for IB device %s, port %u",
+	    ibdev_name, port);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_ibendport_key_create)
+
+void sepol_ibendport_key_unpack(const sepol_ibendport_key_t *key,
+				const char **ibdev_name, int *port)
+{
+	*ibdev_name = key->ibdev_name;
+	*port = key->port;
+}
+
+hidden_def(sepol_ibendport_key_unpack)
+
+int sepol_ibendport_key_extract(sepol_handle_t *handle,
+				const sepol_ibendport_t *ibendport,
+				sepol_ibendport_key_t **key_ptr)
+{
+	if (sepol_ibendport_key_create
+	    (handle, ibendport->ibdev_name, ibendport->port, key_ptr) < 0) {
+		ERR(handle, "could not extract key from ibendport device %s port %d",
+		    ibendport->ibdev_name,
+		    ibendport->port);
+
+		return STATUS_ERR;
+	}
+
+	return STATUS_SUCCESS;
+}
+
+void sepol_ibendport_key_free(sepol_ibendport_key_t *key)
+{
+	if (!key)
+		return;
+	free(key->ibdev_name);
+	free(key);
+}
+
+int sepol_ibendport_compare(const sepol_ibendport_t *ibendport, const sepol_ibendport_key_t *key)
+{
+	int rc;
+
+	rc = strcmp(ibendport->ibdev_name, key->ibdev_name);
+
+	if ((ibendport->port == key->port) && !rc)
+		return 0;
+
+	if (ibendport->port < key->port)
+		return -1;
+	else if (key->port < ibendport->port)
+		return 1;
+	else
+		return rc;
+}
+
+int sepol_ibendport_compare2(const sepol_ibendport_t *ibendport, const sepol_ibendport_t *ibendport2)
+{
+	int rc;
+
+	rc = strcmp(ibendport->ibdev_name, ibendport2->ibdev_name);
+
+	if ((ibendport->port == ibendport2->port) && !rc)
+		return 0;
+
+	if (ibendport->port < ibendport2->port)
+		return -1;
+	else if (ibendport2->port < ibendport->port)
+		return 1;
+	else
+		return rc;
+}
+
+int sepol_ibendport_get_port(const sepol_ibendport_t *ibendport)
+{
+	return ibendport->port;
+}
+
+hidden_def(sepol_ibendport_get_port)
+
+void sepol_ibendport_set_port(sepol_ibendport_t *ibendport, int port)
+{
+	ibendport->port = port;
+}
+
+hidden_def(sepol_ibendport_set_port)
+
+int sepol_ibendport_get_ibdev_name(sepol_handle_t *handle,
+				   const sepol_ibendport_t *ibendport,
+				   char **ibdev_name)
+{
+	char *tmp_ibdev_name = NULL;
+
+	if (sepol_ibendport_alloc_ibdev_name(handle, &tmp_ibdev_name) < 0)
+		goto err;
+
+	strncpy(tmp_ibdev_name, ibendport->ibdev_name, IB_DEVICE_NAME_MAX);
+	*ibdev_name = tmp_ibdev_name;
+	return STATUS_SUCCESS;
+
+err:
+	free(tmp_ibdev_name);
+	ERR(handle, "could not get ibendport ibdev_name");
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_ibendport_get_ibdev_name)
+
+int sepol_ibendport_set_ibdev_name(sepol_handle_t *handle,
+				   sepol_ibendport_t *ibendport,
+				   const char *ibdev_name)
+{
+	char *tmp = NULL;
+
+	if (sepol_ibendport_alloc_ibdev_name(handle, &tmp) < 0)
+		goto err;
+
+	strncpy(tmp, ibdev_name, IB_DEVICE_NAME_MAX);
+	free(ibendport->ibdev_name);
+	ibendport->ibdev_name = tmp;
+	return STATUS_SUCCESS;
+
+err:
+	free(tmp);
+	ERR(handle, "could not set ibendport subnet prefix to %s", ibdev_name);
+	return STATUS_ERR;
+}
+
+hidden_def(sepol_ibendport_set_ibdev_name)
+
+/* Create */
+int sepol_ibendport_create(sepol_handle_t *handle, sepol_ibendport_t **ibendport)
+{
+	sepol_ibendport_t *tmp_ibendport = (sepol_ibendport_t *)malloc(sizeof(sepol_ibendport_t));
+
+	if (!tmp_ibendport) {
+		ERR(handle, "out of memory, could not create ibendport record");
+		return STATUS_ERR;
+	}
+
+	tmp_ibendport->ibdev_name = NULL;
+	tmp_ibendport->port = 0;
+	tmp_ibendport->con = NULL;
+	*ibendport = tmp_ibendport;
+
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_ibendport_create)
+
+/* Deep copy clone */
+int sepol_ibendport_clone(sepol_handle_t *handle,
+			  const sepol_ibendport_t *ibendport,
+			  sepol_ibendport_t **ibendport_ptr)
+{
+	sepol_ibendport_t *new_ibendport = NULL;
+
+	if (sepol_ibendport_create(handle, &new_ibendport) < 0)
+		goto err;
+
+	if (sepol_ibendport_alloc_ibdev_name(handle, &new_ibendport->ibdev_name) < 0)
+		goto omem;
+
+	strncpy(new_ibendport->ibdev_name, ibendport->ibdev_name, IB_DEVICE_NAME_MAX);
+	new_ibendport->port = ibendport->port;
+
+	if (ibendport->con &&
+	    (sepol_context_clone(handle, ibendport->con, &new_ibendport->con) < 0))
+		goto err;
+
+	*ibendport_ptr = new_ibendport;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+
+err:
+	ERR(handle, "could not clone ibendport record");
+	sepol_ibendport_free(new_ibendport);
+	return STATUS_ERR;
+}
+
+/* Destroy */
+void sepol_ibendport_free(sepol_ibendport_t *ibendport)
+{
+	if (!ibendport)
+		return;
+
+	free(ibendport->ibdev_name);
+	sepol_context_free(ibendport->con);
+	free(ibendport);
+}
+
+hidden_def(sepol_ibendport_free)
+
+/* Context */
+sepol_context_t *sepol_ibendport_get_con(const sepol_ibendport_t *ibendport)
+{
+	return ibendport->con;
+}
+
+hidden_def(sepol_ibendport_get_con)
+
+int sepol_ibendport_set_con(sepol_handle_t *handle,
+			    sepol_ibendport_t *ibendport, sepol_context_t *con)
+{
+	sepol_context_t *newcon;
+
+	if (sepol_context_clone(handle, con, &newcon) < 0) {
+		ERR(handle, "out of memory, could not set ibendport context");
+		return STATUS_ERR;
+	}
+
+	sepol_context_free(ibendport->con);
+	ibendport->con = newcon;
+	return STATUS_SUCCESS;
+}
+
+hidden_def(sepol_ibendport_set_con)
diff --git a/libsepol/src/ibendports.c b/libsepol/src/ibendports.c
new file mode 100644
index 00000000..0438093e
--- /dev/null
+++ b/libsepol/src/ibendports.c
@@ -0,0 +1,255 @@
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "context.h"
+#include "handle.h"
+
+#include <sepol/policydb/policydb.h>
+#include "ibendport_internal.h"
+
+/* Create a low level ibendport structure from
+ * a high level representation
+ */
+static int ibendport_from_record(sepol_handle_t *handle,
+				 const policydb_t *policydb,
+				 ocontext_t **ibendport,
+				 const sepol_ibendport_t *data)
+{
+	ocontext_t *tmp_ibendport = NULL;
+	context_struct_t *tmp_con = NULL;
+	char *ibdev_name = NULL;
+	int port = sepol_ibendport_get_port(data);
+
+	tmp_ibendport = (ocontext_t *)calloc(1, sizeof(ocontext_t));
+	if (!tmp_ibendport)
+		goto omem;
+
+	if (sepol_ibendport_alloc_ibdev_name(handle,
+					     &tmp_ibendport->u.ibendport.dev_name) < 0)
+		goto omem;
+
+	if (sepol_ibendport_get_ibdev_name(handle,
+					   data,
+					   &ibdev_name) < 0)
+		goto err;
+
+	strncpy(tmp_ibendport->u.ibendport.dev_name, ibdev_name, IB_DEVICE_NAME_MAX);
+
+	free(ibdev_name);
+	ibdev_name = NULL;
+
+	tmp_ibendport->u.ibendport.port = port;
+
+	/* Context */
+	if (context_from_record(handle, policydb, &tmp_con,
+				sepol_ibendport_get_con(data)) < 0)
+		goto err;
+	context_cpy(&tmp_ibendport->context[0], tmp_con);
+	context_destroy(tmp_con);
+	free(tmp_con);
+	tmp_con = NULL;
+
+	*ibendport = tmp_ibendport;
+	return STATUS_SUCCESS;
+
+omem:
+	ERR(handle, "out of memory");
+
+err:
+	if (tmp_ibendport) {
+		context_destroy(&tmp_ibendport->context[0]);
+		free(tmp_ibendport);
+	}
+	context_destroy(tmp_con);
+	free(tmp_con);
+	free(ibdev_name);
+	ERR(handle, "could not create ibendport structure");
+	return STATUS_ERR;
+}
+
+static int ibendport_to_record(sepol_handle_t *handle,
+			       const policydb_t *policydb,
+			       ocontext_t *ibendport,
+			       sepol_ibendport_t **record)
+{
+	int port = ibendport->u.ibendport.port;
+	context_struct_t *con = &ibendport->context[0];
+
+	sepol_context_t *tmp_con = NULL;
+	sepol_ibendport_t *tmp_record = NULL;
+
+	if (sepol_ibendport_create(handle, &tmp_record) < 0)
+		goto err;
+
+	if (sepol_ibendport_set_ibdev_name(handle, tmp_record,
+					   ibendport->u.ibendport.dev_name) < 0)
+		goto err;
+
+	sepol_ibendport_set_port(tmp_record, port);
+
+	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
+		goto err;
+
+	if (sepol_ibendport_set_con(handle, tmp_record, tmp_con) < 0)
+		goto err;
+
+	sepol_context_free(tmp_con);
+	*record = tmp_record;
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not convert ibendport to record");
+	sepol_context_free(tmp_con);
+	sepol_ibendport_free(tmp_record);
+	return STATUS_ERR;
+}
+
+/* Return the number of ibendports */
+extern int sepol_ibendport_count(sepol_handle_t *handle __attribute__ ((unused)),
+				 const sepol_policydb_t *p, unsigned int *response)
+{
+	unsigned int count = 0;
+	ocontext_t *c, *head;
+	const policydb_t *policydb = &p->p;
+
+	head = policydb->ocontexts[OCON_IBENDPORT];
+	for (c = head; c; c = c->next)
+		count++;
+
+	*response = count;
+
+	handle = NULL;
+	return STATUS_SUCCESS;
+}
+
+/* Check if a ibendport exists */
+int sepol_ibendport_exists(sepol_handle_t *handle __attribute__ ((unused)),
+			   const sepol_policydb_t *p,
+			   const sepol_ibendport_key_t *key, int *response)
+{
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	int port;
+	const char *ibdev_name;
+
+	sepol_ibendport_key_unpack(key, &ibdev_name, &port);
+
+	head = policydb->ocontexts[OCON_IBENDPORT];
+	for (c = head; c; c = c->next) {
+		const char *ibdev_name2 = c->u.ibendport.dev_name;
+		int port2 = c->u.ibendport.port;
+
+		if (port2 == port &&
+		    (!strcmp(ibdev_name, ibdev_name2))) {
+			*response = 1;
+			return STATUS_SUCCESS;
+		}
+	}
+
+	*response = 0;
+	return STATUS_SUCCESS;
+}
+
+int sepol_ibendport_query(sepol_handle_t *handle,
+			  const sepol_policydb_t *p,
+			  const sepol_ibendport_key_t *key,
+			  sepol_ibendport_t **response)
+{
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	int port;
+	const char *ibdev_name;
+
+	sepol_ibendport_key_unpack(key, &ibdev_name, &port);
+
+	head = policydb->ocontexts[OCON_IBENDPORT];
+	for (c = head; c; c = c->next) {
+		const char *ibdev_name2 = c->u.ibendport.dev_name;
+		int port2 = c->u.ibendport.port;
+
+		if (port2 == port &&
+		    (!strcmp(ibdev_name, ibdev_name2))) {
+			if (ibendport_to_record(handle, policydb, c, response) < 0)
+				goto err;
+			return STATUS_SUCCESS;
+		}
+	}
+
+	*response = NULL;
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not query ibendport, IB device: %s port %u",
+	    ibdev_name, port);
+	return STATUS_ERR;
+}
+
+/* Load a ibendport into policy */
+int sepol_ibendport_modify(sepol_handle_t *handle,
+			   sepol_policydb_t *p,
+			   const sepol_ibendport_key_t *key,
+			   const sepol_ibendport_t *data)
+{
+	policydb_t *policydb = &p->p;
+	ocontext_t *ibendport = NULL;
+	int port;
+	const char *ibdev_name;
+
+	sepol_ibendport_key_unpack(key, &ibdev_name, &port);
+
+	if (ibendport_from_record(handle, policydb, &ibendport, data) < 0)
+		goto err;
+
+	/* Attach to context list */
+	ibendport->next = policydb->ocontexts[OCON_IBENDPORT];
+	policydb->ocontexts[OCON_IBENDPORT] = ibendport;
+
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not load ibendport %s/%d",
+	    ibdev_name, port);
+	if (ibendport) {
+		context_destroy(&ibendport->context[0]);
+		free(ibendport);
+	}
+	return STATUS_ERR;
+}
+
+int sepol_ibendport_iterate(sepol_handle_t *handle,
+			    const sepol_policydb_t *p,
+			    int (*fn)(const sepol_ibendport_t *ibendport,
+				      void *fn_arg), void *arg)
+{
+	const policydb_t *policydb = &p->p;
+	ocontext_t *c, *head;
+	sepol_ibendport_t *ibendport = NULL;
+
+	head = policydb->ocontexts[OCON_IBENDPORT];
+	for (c = head; c; c = c->next) {
+		int status;
+
+		if (ibendport_to_record(handle, policydb, c, &ibendport) < 0)
+			goto err;
+
+		/* Invoke handler */
+		status = fn(ibendport, arg);
+		if (status < 0)
+			goto err;
+
+		sepol_ibendport_free(ibendport);
+		ibendport = NULL;
+
+		/* Handler requested exit */
+		if (status > 0)
+			break;
+	}
+
+	return STATUS_SUCCESS;
+
+err:
+	ERR(handle, "could not iterate over ibendports");
+	sepol_ibendport_free(ibendport);
+	return STATUS_ERR;
+}
diff --git a/python/semanage/semanage b/python/semanage/semanage
index 11b56e22..313537c5 100644
--- a/python/semanage/semanage
+++ b/python/semanage/semanage
@@ -61,6 +61,9 @@ usage_port_dict = {' --add': ('-t TYPE', '-p PROTOCOL', '-r RANGE', '(', 'port_n
 usage_ibpkey = "semanage ibpkey [-h] [-n] [-N] [-s STORE] ["
 usage_ibpkey_dict = {' --add': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --modify': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --delete': ('-x SUBNET_PREFIX', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
 
+usage_ibendport = "semanage ibendport [-h] [-n] [-N] [-s STORE] ["
+usage_ibendport_dict = {' --add': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --modify': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --delete': ('-z IBDEV_NAME', '-r RANGE''(', 'port', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
+
 usage_node = "semanage node [-h] [-n] [-N] [-S STORE] ["
 usage_node_dict = {' --add': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --modify': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --delete': ('-M NETMASK', '-p PROTOCOL', 'node'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
 
@@ -152,6 +155,10 @@ def ibpkey_ini():
     OBJECT = seobject.ibpkeyRecords(store)
     return OBJECT
 
+def ibendport_ini():
+    OBJECT = seobject.ibendportRecords(store)
+    return OBJECT
+
 def module_ini():
     OBJECT = seobject.moduleRecords(store)
     return OBJECT
@@ -187,8 +194,7 @@ def dontaudit_ini():
     return OBJECT
 
 # define dictonary for seobject OBEJCTS
-object_dict = {'login': login_ini, 'user': user_ini, 'port': port_ini, 'module': module_ini, 'interface': interface_ini, 'node': node_ini, 'fcontext': fcontext_ini, 'boolean': boolean_ini, 'permissive': permissive_ini, 'dontaudit': dontaudit_ini, 'ibpkey': ibpkey_ini}
-
+object_dict = {'login': login_ini, 'user': user_ini, 'port': port_ini, 'module': module_ini, 'interface': interface_ini, 'node': node_ini, 'fcontext': fcontext_ini, 'boolean': boolean_ini, 'permissive': permissive_ini, 'dontaudit': dontaudit_ini, 'ibpkey': ibpkey_ini, 'ibendport': ibendport_ini}
 
 def generate_custom_usage(usage_text, usage_dict):
     # generate custom usage from given text and dictonary
@@ -303,6 +309,10 @@ def parser_add_subnet_prefix(parser, name):
     Subnet prefix for  the specified infiniband ibpkey.
 '''))
 
+def parser_add_ibdev_name(parser, name):
+    parser.add_argument('-z', '--ibdev_name', help=_('''
+    Name for the specified infiniband end port.
+'''))
 
 def parser_add_modify(parser, name):
     parser.add_argument('-m', '--modify', dest='action', action='store_const', const='modify', help=_("Modify a record of the %s object type") % name)
@@ -567,6 +577,49 @@ def setupPkeyParser(subparsers):
     ibpkeyParser.add_argument('ibpkey', nargs='?', default=None, help=_('pkey | pkey_range'))
     ibpkeyParser.set_defaults(func=handlePkey)
 
+def handleIbendport(args):
+    ibendport_args = {'list': [('ibendport', 'type', 'ibdev_name'), ('')], 'add': [('locallist'), ('type', 'ibendport', 'ibdev_name'), ('')], 'modify': [('localist'), ('ibendport', 'ibdev_name')], 'delete': [('locallist'), ('ibendport', 'ibdev_name')], 'extract': [('locallist', 'ibendport', 'type', 'ibdev_name'), ('')], 'deleteall': [('locallist'), ('')]}
+
+    handle_opts(args, ibendport_args, args.action)
+
+    OBJECT = object_dict['ibendport']()
+    OBJECT.set_reload(args.noreload)
+
+    if args.action is "add":
+        OBJECT.add(args.ibendport, args.ibdev_name, args.range, args.type)
+    if args.action is "modify":
+        OBJECT.modify(args.ibendport, args.ibdev_name, args.range, args.type)
+    if args.action is "delete":
+        OBJECT.delete(args.ibendport, args.ibdev_name)
+    if args.action is "list":
+        OBJECT.list(args.noheading, args.locallist)
+    if args.action is "deleteall":
+        OBJECT.deleteall()
+    if args.action is "extract":
+        for i in OBJECT.customized():
+            print("ibendport %s" % str(i))
+
+
+def setupIbendportParser(subparsers):
+    generated_usage = generate_custom_usage(usage_ibendport, usage_ibendport_dict)
+    ibendportParser = subparsers.add_parser('ibendport', usage=generated_usage, help=_('Manage infiniband end port type definitions'))
+    parser_add_locallist(ibendportParser, "ibendport")
+    parser_add_noheading(ibendportParser, "ibendport")
+    parser_add_noreload(ibendportParser, "ibendport")
+    parser_add_store(ibendportParser, "ibendport")
+
+    ibendport_action = ibendportParser.add_mutually_exclusive_group(required=True)
+    parser_add_add(ibendport_action, "ibendport")
+    parser_add_delete(ibendport_action, "ibendport")
+    parser_add_modify(ibendport_action, "ibendport")
+    parser_add_list(ibendport_action, "ibendport")
+    parser_add_extract(ibendport_action, "ibendport")
+    parser_add_deleteall(ibendport_action, "ibendport")
+    parser_add_type(ibendportParser, "ibendport")
+    parser_add_range(ibendportParser, "ibendport")
+    parser_add_ibdev_name(ibendportParser, "ibendport")
+    ibendportParser.add_argument('ibendport', nargs='?', default=None, help=_('ibendport'))
+    ibendportParser.set_defaults(func=handleIbendport)
 
 def handleInterface(args):
     interface_args = {'list': [('interface'), ('')], 'add': [('locallist'), ('type', 'interface')], 'modify': [('locallist'), ('type', 'interface')], 'delete': [('locallist'), ('interface')], 'extract': [('locallist', 'interface', 'type'), ('')], 'deleteall': [('locallist'), ('')]}
@@ -907,6 +960,7 @@ def createCommandParser():
     setupUserParser(subparsers)
     setupPortParser(subparsers)
     setupPkeyParser(subparsers)
+    setupIbendportParser(subparsers)
     setupInterfaceParser(subparsers)
     setupModuleParser(subparsers)
     setupNodeParser(subparsers)
diff --git a/python/semanage/seobject.py b/python/semanage/seobject.py
index 297a2496..61be6198 100644
--- a/python/semanage/seobject.py
+++ b/python/semanage/seobject.py
@@ -1565,6 +1565,245 @@ class ibpkeyRecords(semanageRecords):
                 rec += ", %s" % p
             print rec
 
+class ibendportRecords(semanageRecords):
+    try:
+        q = setools.TypeQuery(setools.SELinuxPolicy(sepolicy.get_installed_policy()), attrs=["ibendport_type"])
+        valid_types = set(str(t) for t in q.results())
+    except:
+        valid_types = []
+
+    def __init__(self, store=""):
+        semanageRecords.__init__(self, store)
+
+    def __genkey(self, ibendport, ibdev_name):
+	if ibdev_name == "":
+            raise ValueError(_("IB device name is required"))
+
+        port = int(ibendport)
+
+        if port > 255 or port < 1:
+            raise ValueError(_("Invalid Port Number"))
+
+        (rc, k) = semanage_ibendport_key_create(self.sh, ibdev_name, port)
+        if rc < 0:
+            raise ValueError(_("Could not create a key for ibendport %s/%s") % (ibdev_name, ibendport))
+        return (k, ibdev_name, port)
+
+    def __add(self, ibendport, ibdev_name, serange, type):
+        if is_mls_enabled == 1:
+            if serange == "":
+                serange = "s0"
+            else:
+                serange = untranslate(serange)
+
+        if type == "":
+            raise ValueError(_("Type is required"))
+
+        if type not in self.valid_types:
+            raise ValueError(_("Type %s is invalid, must be an ibendport type") % type)
+        (k, ibendport, port) = self.__genkey(ibendport, ibdev_name)
+
+        (rc, exists) = semanage_ibendport_exists(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibendport %s/%s is defined") % (ibdev_name, port))
+        if exists:
+            raise ValueError(_("ibendport %s/%s already defined") % (ibdev_name, port))
+
+        (rc, p) = semanage_ibendport_create(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not create ibendport for %s/%s") % (ibdev_name, port))
+
+        semanage_ibendport_set_ibdev_name(self.sh, p, ibdev_name)
+        semanage_ibendport_set_port(p, port)
+        (rc, con) = semanage_context_create(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not create context for %s/%s") % (ibdev_name, port))
+
+        rc = semanage_context_set_user(self.sh, con, "system_u")
+        if rc < 0:
+            raise ValueError(_("Could not set user in ibendport context for %s/%s") % (ibdev_name, port))
+
+        rc = semanage_context_set_role(self.sh, con, "object_r")
+        if rc < 0:
+            raise ValueError(_("Could not set role in ibendport context for %s/%s") % (ibdev_name, port))
+
+        rc = semanage_context_set_type(self.sh, con, type)
+        if rc < 0:
+            raise ValueError(_("Could not set type in ibendport context for %s/%s") % (ibdev_name, port))
+
+        if (is_mls_enabled == 1) and (serange != ""):
+            rc = semanage_context_set_mls(self.sh, con, serange)
+            if rc < 0:
+                raise ValueError(_("Could not set mls fields in ibendport context for %s/%s") % (ibdev_name, port))
+
+        rc = semanage_ibendport_set_con(self.sh, p, con)
+        if rc < 0:
+            raise ValueError(_("Could not set ibendport context for %s/%s") % (ibdev_name, port))
+
+        rc = semanage_ibendport_modify_local(self.sh, k, p)
+        if rc < 0:
+            raise ValueError(_("Could not add ibendport %s/%s") % (ibdev_name, port))
+
+        semanage_context_free(con)
+        semanage_ibendport_key_free(k)
+        semanage_ibendport_free(p)
+
+    def add(self, ibendport, ibdev_name, serange, type):
+        self.begin()
+        self.__add(ibendport, ibdev_name, serange, type)
+        self.commit()
+
+    def __modify(self, ibendport, ibdev_name, serange, setype):
+        if serange == "" and setype == "":
+            if is_mls_enabled == 1:
+                raise ValueError(_("Requires setype or serange"))
+            else:
+                raise ValueError(_("Requires setype"))
+
+        if setype and setype not in self.valid_types:
+            raise ValueError(_("Type %s is invalid, must be an ibendport type") % setype)
+
+        (k, ibdev_name, port) = self.__genkey(ibendport, ibdev_name)
+
+        (rc, exists) = semanage_ibendport_exists(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibendport %s/%s is defined") % (ibdev_name, ibendport))
+        if not exists:
+            raise ValueError(_("ibendport %s/%s is not defined") % (ibdev_name, ibendport))
+
+        (rc, p) = semanage_ibendport_query(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not query ibendport %s/%s") % (ibdev_name, ibendport))
+
+        con = semanage_ibendport_get_con(p)
+
+        if (is_mls_enabled == 1) and (serange != ""):
+            semanage_context_set_mls(self.sh, con, untranslate(serange))
+        if setype != "":
+            semanage_context_set_type(self.sh, con, setype)
+
+        rc = semanage_ibendport_modify_local(self.sh, k, p)
+        if rc < 0:
+            raise ValueError(_("Could not modify ibendport %s/%s") % (ibdev_name, ibendport))
+
+        semanage_ibendport_key_free(k)
+        semanage_ibendport_free(p)
+
+    def modify(self, ibendport, ibdev_name, serange, setype):
+        self.begin()
+        self.__modify(ibendport, ibdev_name, serange, setype)
+        self.commit()
+
+    def deleteall(self):
+        (rc, plist) = semanage_ibendport_list_local(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not list the ibendports"))
+
+        self.begin()
+
+        for ibendport in plist:
+            (rc, ibdev_name) = semanage_ibendport_get_ibdev_name(self.sh, ibendport)
+            port = semanage_ibendport_get_port(ibendport)
+            (k, ibdev_name, port) = self.__genkey(str(port), ibdev_name)
+            if rc < 0:
+                raise ValueError(_("Could not create a key for %s/%d") % (ibdevname, port))
+
+            rc = semanage_ibendport_del_local(self.sh, k)
+            if rc < 0:
+                raise ValueError(_("Could not delete the ibendport %s/%d") % (ibdev_name, port))
+            semanage_ibendport_key_free(k)
+
+        self.commit()
+
+    def __delete(self, ibendport, ibdev_name):
+        (k, ibdev_name, port) = self.__genkey(ibendport, ibdev_name)
+        (rc, exists) = semanage_ibendport_exists(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibendport %s/%s is defined") % (ibdev_name, ibendport))
+        if not exists:
+            raise ValueError(_("ibendport %s/%s is not defined") % (ibdev_name, ibendport))
+
+        (rc, exists) = semanage_ibendport_exists_local(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not check if ibendport %s/%s is defined") % (ibdev_name, ibendport))
+        if not exists:
+            raise ValueError(_("ibendport %s/%s is defined in policy, cannot be deleted") % (ibdev_name, ibendport))
+
+        rc = semanage_ibendport_del_local(self.sh, k)
+        if rc < 0:
+            raise ValueError(_("Could not delete ibendport %s/%s") % (ibdev_name, ibendport))
+
+        semanage_ibendport_key_free(k)
+
+    def delete(self, ibendport, ibdev_name):
+        self.begin()
+        self.__delete(ibendport, ibdev_name)
+        self.commit()
+
+    def get_all(self, locallist=0):
+        ddict = {}
+        if locallist:
+            (rc, self.plist) = semanage_ibendport_list_local(self.sh)
+        else:
+            (rc, self.plist) = semanage_ibendport_list(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not list ibendports"))
+
+        for ibendport in self.plist:
+            con = semanage_ibendport_get_con(ibendport)
+            ctype = semanage_context_get_type(con)
+            if ctype == "reserved_ibendport_t":
+                continue
+            level = semanage_context_get_mls(con)
+            (rc, ibdev_name) = semanage_ibendport_get_ibdev_name(self.sh, ibendport)
+            port = semanage_ibendport_get_port(ibendport)
+            ddict[(port, ibdev_name)] = (ctype, level)
+        return ddict
+
+    def get_all_by_type(self, locallist=0):
+        ddict = {}
+        if locallist:
+            (rc, self.plist) = semanage_ibendport_list_local(self.sh)
+        else:
+            (rc, self.plist) = semanage_ibendport_list(self.sh)
+        if rc < 0:
+            raise ValueError(_("Could not list ibendports"))
+
+        for ibendport in self.plist:
+            con = semanage_ibendport_get_con(ibendport)
+            ctype = semanage_context_get_type(con)
+            (rc, ibdev_name) = semanage_ibendport_get_ibdev_name(self.sh, ibendport)
+            port = semanage_ibendport_get_port(ibendport)
+            if (ctype, ibdev_name) not in ddict.keys():
+                ddict[(ctype, ibdev_name)] = []
+            ddict[(ctype, ibdev_name)].append("0x%x" % port)
+        return ddict
+
+    def customized(self):
+        l = []
+        ddict = self.get_all(True)
+        keys = ddict.keys()
+        keys.sort()
+        for k in keys:
+            l.append("-a -t %s -x %s %s" % (ddict[k][0], k[2], k[0]))
+        return l
+
+    def list(self, heading=1, locallist=0):
+        ddict = self.get_all_by_type(locallist)
+        keys = ddict.keys()
+        if len(keys) == 0:
+            return
+        keys.sort()
+
+        if heading:
+            print "%-30s %-18s %s\n" % (_("SELinux IB End Port Type"), _("IB Device Name"), _("Port Number"))
+        for i in keys:
+            rec = "%-30s %-18s " % i
+            rec += "%s" % ddict[i][0]
+            for p in ddict[i][1:]:
+                rec += ", %s" % p
+            print rec
+
 class nodeRecords(semanageRecords):
     try:
         valid_types = list(list(sepolicy.info(sepolicy.ATTRIBUTE, "node_type"))[0]["types"])
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 9/9] semanage: Update man pages for infiniband
  2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
                   ` (7 preceding siblings ...)
  2017-05-18 22:25 ` [PATCH v2 8/9] semanage: Update semanage to allow runtime labeling of ibendports Dan Jurgens
@ 2017-05-18 22:25 ` Dan Jurgens
  8 siblings, 0 replies; 11+ messages in thread
From: Dan Jurgens @ 2017-05-18 22:25 UTC (permalink / raw)
  To: selinux

From: Daniel Jurgens <danielj@mellanox.com>

Update the main man page and add specific pages for ibpkeys and
ibendports.

Signed-off-by: Daniel Jurgens <danielj@mellanox.com>
---
 python/semanage/semanage-ibendport.8 | 66 ++++++++++++++++++++++++++++++++++++
 python/semanage/semanage-ibpkey.8    | 66 ++++++++++++++++++++++++++++++++++++
 python/semanage/semanage.8           | 16 ++++++---
 3 files changed, 144 insertions(+), 4 deletions(-)
 create mode 100644 python/semanage/semanage-ibendport.8
 create mode 100644 python/semanage/semanage-ibpkey.8

diff --git a/python/semanage/semanage-ibendport.8 b/python/semanage/semanage-ibendport.8
new file mode 100644
index 00000000..c3753a27
--- /dev/null
+++ b/python/semanage/semanage-ibendport.8
@@ -0,0 +1,66 @@
+.TH "semanage-ibendport" "8" "20170508" "" ""
+.SH "NAME"
+.B semanage\-ibendport \- SELinux Policy Management ibendport mapping tool
+.SH "SYNOPSIS"
+.B semanage ibendport [\-h] [\-n] [\-N] [\-S STORE] [ \-\-add \-t TYPE \-z IBDEV_NAME \-r RANGE port | \-\-delete \-z IBDEV_NAME port | \-\-deleteall  | \-\-extract  | \-\-list [\-C] | \-\-modify \-t TYPE \-z IBDEV_NAME \-r RANGE port ]
+
+.SH "DESCRIPTION"
+semanage is used to configure certain elements of SELinux policy without requiring modification to or recompilation from policy sources.  semanage ibendport controls the ibendport number to ibendport type definitions.
+
+.SH "OPTIONS"
+.TP
+.I  \-h, \-\-help
+show this help message and exit
+.TP
+.I   \-n, \-\-noheading
+Do not print heading when listing the specified object type
+.TP
+.I   \-N, \-\-noreload
+Do not reload policy after commit
+.TP
+.I   \-S STORE, \-\-store STORE
+Select an alternate SELinux Policy Store to manage
+.TP
+.I   \-C, \-\-locallist
+List local customizations
+.TP
+.I   \-a, \-\-add
+Add a record of the specified object type
+.TP
+.I   \-d, \-\-delete
+Delete a record of the specified object type
+.TP
+.I   \-m, \-\-modify
+Modify a record of the specified object type
+.TP
+.I   \-l, \-\-list
+List records of the specified object type
+.TP
+.I   \-E, \-\-extract
+Extract customizable commands, for use within a transaction
+.TP
+.I   \-D, \-\-deleteall
+Remove all local customizations
+.TP
+.I   \-t TYPE, \-\-type TYPE
+SELinux type for the object
+.TP
+.I   \-r RANGE, \-\-range RANGE
+MLS/MCS Security Range (MLS/MCS Systems only) SELinux Range for SELinux login mapping defaults to the SELinux user record range. SELinux Range for SELinux user defaults to s0.
+.TP
+.I \-z IBDEV_NAME, \-\-ibdev_name IBDEV_NAME
+The name of the infiniband device for the port to be labeled.  (ex. mlx5_0)
+
+.SH EXAMPLE
+.nf
+List all ibendport definitions
+# semanage ibendport \-l
+Label mlx4_0 port 2.
+# semanage ibendport \-a \-t allowed_ibendport_t \-z mlx4_0 2
+
+.SH "SEE ALSO"
+.BR selinux (8),
+.BR semanage (8)
+
+.SH "AUTHOR"
+This man page was written by Daniel Walsh <dwalsh@redhat.com>
diff --git a/python/semanage/semanage-ibpkey.8 b/python/semanage/semanage-ibpkey.8
new file mode 100644
index 00000000..2da4f546
--- /dev/null
+++ b/python/semanage/semanage-ibpkey.8
@@ -0,0 +1,66 @@
+.TH "semanage-ibpkey" "8" "20170508" "" ""
+.SH "NAME"
+.B semanage\-ibpkey \- SELinux Policy Management ibpkey mapping tool
+.SH "SYNOPSIS"
+.B semanage ibpkey [\-h] [\-n] [\-N] [\-S STORE] [ \-\-add \-t TYPE \-x SUBNET_PREFIX \-r RANGE ibpkey_name | ibpkey_range | \-\-delete \-x SUBNET_PREFIX ibpkey_name | ibpkey_range | \-\-deleteall  | \-\-extract  | \-\-list [\-C] | \-\-modify \-t TYPE \-x SUBNET_PREFIX \-r RANGE ibpkey_name | ibpkey_range ]
+
+.SH "DESCRIPTION"
+semanage is used to configure certain elements of SELinux policy without requiring modification to or recompilation from policy sources.  semanage ibpkey controls the ibpkey number to ibpkey type definitions.
+
+.SH "OPTIONS"
+.TP
+.I  \-h, \-\-help
+show this help message and exit
+.TP
+.I   \-n, \-\-noheading
+Do not print heading when listing the specified object type
+.TP
+.I   \-N, \-\-noreload
+Do not reload policy after commit
+.TP
+.I   \-S STORE, \-\-store STORE
+Select an alternate SELinux Policy Store to manage
+.TP
+.I   \-C, \-\-locallist
+List local customizations
+.TP
+.I   \-a, \-\-add
+Add a record of the specified object type
+.TP
+.I   \-d, \-\-delete
+Delete a record of the specified object type
+.TP
+.I   \-m, \-\-modify
+Modify a record of the specified object type
+.TP
+.I   \-l, \-\-list
+List records of the specified object type
+.TP
+.I   \-E, \-\-extract
+Extract customizable commands, for use within a transaction
+.TP
+.I   \-D, \-\-deleteall
+Remove all local customizations
+.TP
+.I   \-t TYPE, \-\-type TYPE
+SELinux type for the object
+.TP
+.I   \-r RANGE, \-\-range RANGE
+MLS/MCS Security Range (MLS/MCS Systems only) SELinux Range for SELinux login mapping defaults to the SELinux user record range. SELinux Range for SELinux user defaults to s0.
+.TP
+.I \-x SUBNET_PREFIX, \-\-subnet_prefix SUBNET_PREFIX
+Subnet prefix for the specified pkey or range of pkeys.
+
+.SH EXAMPLE
+.nf
+List all ibpkey definitions
+# semanage ibpkey \-l
+Label pkey 0x8FFF (limited membership default pkey) as a default pkey type
+# semanage ibpkey \-a \-t default_ibpkey_t \-x fe80:: 0x8FFF
+
+.SH "SEE ALSO"
+.BR selinux (8),
+.BR semanage (8)
+
+.SH "AUTHOR"
+This man page was written by Daniel Walsh <dwalsh@redhat.com>
diff --git a/python/semanage/semanage.8 b/python/semanage/semanage.8
index abc47360..0bdb90f4 100644
--- a/python/semanage/semanage.8
+++ b/python/semanage/semanage.8
@@ -3,7 +3,7 @@
 semanage \- SELinux Policy Management tool
 
 .SH "SYNOPSIS"
-.B semanage                {import,export,login,user,port,interface,module,node,fcontext,boolean,permissive,dontaudit}
+.B semanage                {import,export,login,user,port,interface,module,node,fcontext,boolean,permissive,dontaudit,ibpkey,ibendport}
                 ...
 .B positional arguments:
 
@@ -43,6 +43,12 @@ Manage process type enforcement mode
 .B    dontaudit
 Disable/Enable dontaudit rules in policy
 
+.B    ibpkey
+Manage infiniband pkey type definitions
+
+.B    ibendport
+Manage infiniband end port type definitions
+
 .SH "DESCRIPTION"
 semanage is used to configure certain elements of
 SELinux policy without requiring modification to or recompilation
@@ -50,9 +56,9 @@ from policy sources.  This includes the mapping from Linux usernames
 to SELinux user identities (which controls the initial security context
 assigned to Linux users when they login and bounds their authorized role set)
 as well as security context mappings for various kinds of objects, such
-as network ports, interfaces, and nodes (hosts) as well as the file
-context mapping. See the EXAMPLES section below for some examples
-of common usage.  Note that the semanage login command deals with the
+as network ports, interfaces, infiniband pkeys and endports, and nodes (hosts)
+as well as the file context mapping. See the EXAMPLES section below for some
+examples of common usage.  Note that the semanage login command deals with the
 mapping from Linux usernames (logins) to SELinux user identities,
 while the semanage user command deals with the mapping from SELinux
 user identities to authorized role sets.  In most cases, only the
@@ -79,6 +85,8 @@ List help information
 .BR semanage-permissive (8),
 .BR semanage-port (8),
 .BR semanage-user (8)
+.BR semanage-ibkey (8),
+.BR semanage-ibendport (8),
 
 .SH "AUTHOR"
 This man page was written by Daniel Walsh <dwalsh@redhat.com>
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 7/9] semanage: Update semanage to allow runtime labeling of Infiniband Pkeys
  2017-05-18 22:25 ` [PATCH v2 7/9] semanage: Update semanage to allow runtime labeling of Infiniband Pkeys Dan Jurgens
@ 2017-05-19 15:36   ` Stephen Smalley
  0 siblings, 0 replies; 11+ messages in thread
From: Stephen Smalley @ 2017-05-19 15:36 UTC (permalink / raw)
  To: Dan Jurgens, selinux

On Fri, 2017-05-19 at 01:25 +0300, Dan Jurgens wrote:
> From: Daniel Jurgens <danielj@mellanox.com>
> 
> Update libsepol and libsemanage to work with pkey records. Add local
> storage for new and modified pkey records in pkeys.local. Update
> semanage
> to parse the pkey command options to add, modify, and delete pkeys.
> 
> Signed-off-by: Daniel Jurgens <danielj@mellanox.com>
> 
> ---
> v1:
> Fixed semanage_pkey_exists -> semanage_ibpkey_exists in delete flow
> in
> seobject.py
> 
> Stephen Smalley:
> - Subnet prefix can't vary in size always 16 bytes, remove size
> field.
> - Removed extraneous change in libsepol/VERSION
> - Removed ifdef DARWIN s6_addr/32 blocks in favor of s6_addr.
> - Got rid of magic constant for subnet prefix size.
> 
> Jason Zaman:
> - Use SETools directly to query types in seobject.py.
> 
> v2:
> Jason Zaman:
> - Use set instead of sorted for valid_types.
> 
> Stephen Smalley:
> - Fix semanage when ibpkey_type attribute isn't defined.
> - Store subnet prefix in 8 bytes.
> - Removed a missed #if DARWIN
> - Use sizeof(struct in6_addr) vs a define.
> ---
>  libsemanage/include/semanage/ibpkey_record.h  |  74 +++++
>  libsemanage/include/semanage/ibpkeys_local.h  |  36 +++
>  libsemanage/include/semanage/ibpkeys_policy.h |  28 ++
>  libsemanage/include/semanage/semanage.h       |   3 +
>  libsemanage/src/direct_api.c                  |  29 +-
>  libsemanage/src/handle.h                      |  36 ++-
>  libsemanage/src/ibpkey_internal.h             |  52 +++
>  libsemanage/src/ibpkey_record.c               | 185 +++++++++++
>  libsemanage/src/ibpkeys_file.c                | 181 +++++++++++
>  libsemanage/src/ibpkeys_local.c               | 179 +++++++++++
>  libsemanage/src/ibpkeys_policy.c              |  52 +++
>  libsemanage/src/ibpkeys_policydb.c            |  62 ++++
>  libsemanage/src/libsemanage.map               |   1 +
>  libsemanage/src/policy_components.c           |   5 +-
>  libsemanage/src/semanage_store.c              |   1 +
>  libsemanage/src/semanage_store.h              |   1 +
>  libsemanage/src/semanageswig.i                |   3 +
>  libsemanage/src/semanageswig_python.i         |  43 +++
>  libsemanage/utils/semanage_migrate_store      |   3 +-
>  libsepol/include/sepol/ibpkey_record.h        |  77 +++++
>  libsepol/include/sepol/ibpkeys.h              |  44 +++
>  libsepol/include/sepol/sepol.h                |   2 +
>  libsepol/src/ibpkey_internal.h                |  21 ++
>  libsepol/src/ibpkey_record.c                  | 445
> ++++++++++++++++++++++++++
>  libsepol/src/ibpkeys.c                        | 269 ++++++++++++++++
>  python/semanage/semanage                      |  60 +++-
>  python/semanage/seobject.py                   | 255 +++++++++++++++
>  27 files changed, 2131 insertions(+), 16 deletions(-)
>  create mode 100644 libsemanage/include/semanage/ibpkey_record.h
>  create mode 100644 libsemanage/include/semanage/ibpkeys_local.h
>  create mode 100644 libsemanage/include/semanage/ibpkeys_policy.h
>  create mode 100644 libsemanage/src/ibpkey_internal.h
>  create mode 100644 libsemanage/src/ibpkey_record.c
>  create mode 100644 libsemanage/src/ibpkeys_file.c
>  create mode 100644 libsemanage/src/ibpkeys_local.c
>  create mode 100644 libsemanage/src/ibpkeys_policy.c
>  create mode 100644 libsemanage/src/ibpkeys_policydb.c
>  create mode 100644 libsepol/include/sepol/ibpkey_record.h
>  create mode 100644 libsepol/include/sepol/ibpkeys.h
>  create mode 100644 libsepol/src/ibpkey_internal.h
>  create mode 100644 libsepol/src/ibpkey_record.c
>  create mode 100644 libsepol/src/ibpkeys.c

> diff --git a/libsepol/src/ibpkey_record.c
> b/libsepol/src/ibpkey_record.c
> new file mode 100644
> index 00000000..c551f411
> --- /dev/null
> +++ b/libsepol/src/ibpkey_record.c
> @@ -0,0 +1,445 @@
> +#include <stdlib.h>
> +#include <string.h>
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#include <errno.h>
> +#include <sepol/ibpkey_record.h>
> +
> +#include "ibpkey_internal.h"
> +#include "context_internal.h"
> +#include "debug.h"
> +
> +struct sepol_ibpkey {
> +	/* Subnet prefix */
> +	char *subnet_prefix;

Why not just struct in6_addr or even just uint64_t and only store the
first two words as in struct ocontext?  
 
> +
> +	/* Low - High range. Same for single ibpkeys. */
> +	int low, high;
> +
> +	/* Context */
> +	sepol_context_t *con;
> +};
> +
> +struct sepol_ibpkey_key {
> +	/* Subnet prefix */
> +	char *subnet_prefix;
> +
> +	/* Low - High range. Same for single ibpkeys. */
> +	int low, high;
> +};
> +
> +/* Converts a string represtation (subnet_prefix_str)
> + * to a numeric representation (subnet_prefix_bytes)
> + */
> +static int ibpkey_parse_subnet_prefix(sepol_handle_t *handle,
> +				      const char *subnet_prefix_str,
> +				      char *subnet_prefix_bytes)
> +{
> +	struct in6_addr in_addr;
> +
> +	if (inet_pton(AF_INET6, subnet_prefix_str, &in_addr) <= 0) {
> +		ERR(handle, "could not parse IPv6 address for ibpkey
> subnet prefix %s: %s",
> +		    subnet_prefix_str, strerror(errno));
> +		return STATUS_ERR;
> +	}
> +
> +	memcpy(subnet_prefix_bytes, in_addr.s6_addr, sizeof(struct
> in6_addr));

Then you can just use uint64_t or struct in6_addr throughout and don't
have to worry about code like this being called unsafely (e.g. with an
inadequately sized subnet_prefix_bytes).

> +
> +	return STATUS_SUCCESS;
> +}
> +

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2017-05-19 15:36 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-18 22:25 [PATCH v2 0/9] SELinux user space support for Infiniband RDMA Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 1/9] checkpolicy: Add support for ibpkeycon labels Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 2/9] libsepol: Add ibpkey ocontext handling Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 3/9] libsepol: Add Infiniband Pkey handling to CIL Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 4/9] checkpolicy: Add support for ibendportcon labels Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 5/9] libsepol: Add ibendport ocontext handling Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 6/9] libsepol: Add IB end port handling to CIL Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 7/9] semanage: Update semanage to allow runtime labeling of Infiniband Pkeys Dan Jurgens
2017-05-19 15:36   ` Stephen Smalley
2017-05-18 22:25 ` [PATCH v2 8/9] semanage: Update semanage to allow runtime labeling of ibendports Dan Jurgens
2017-05-18 22:25 ` [PATCH v2 9/9] semanage: Update man pages for infiniband Dan Jurgens

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.