From: Dan Jurgens <danielj@mellanox.com>
To: selinux@tycho.nsa.gov, linux-security-module@vger.kernel.org
Cc: linux-rdma@vger.kernel.org, yevgenyp@mellanox.com,
Daniel Jurgens <danielj@mellanox.com>
Subject: [RFC PATCH 7/7] selinux: Add a cache for quicker retreival of PKey SIDs
Date: Tue, 5 Apr 2016 00:48:24 +0300 [thread overview]
Message-ID: <1459806504-16135-8-git-send-email-danielj@mellanox.com> (raw)
In-Reply-To: <1459806504-16135-1-git-send-email-danielj@mellanox.com>
From: Daniel Jurgens <danielj@mellanox.com>
It is likely that the SID for the same PKey will be requested many
times. To reduce the time to modify QPs and process MADs use a cache to
store PKey SIDs.
This code is heavily based on the "netif" and "netport" concept
originally developed by James Morris <jmorris@redhat.com> and Paul Moore
<paul@paul-moore.com> (see security/selinux/netif.c and
security/selinux/netport.c for more information)
Signed-off-by: Daniel Jurgens <danielj@mellanox.com>
Reviewed-by: Eli Cohen <eli@mellanox.com>
---
security/selinux/Makefile | 2 +-
security/selinux/hooks.c | 4 +-
security/selinux/include/objsec.h | 6 +
security/selinux/include/pkey.h | 33 ++++++
security/selinux/pkey.c | 220 +++++++++++++++++++++++++++++++++++++
5 files changed, 263 insertions(+), 2 deletions(-)
create mode 100644 security/selinux/include/pkey.h
create mode 100644 security/selinux/pkey.c
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index ad5cd76..2a54c38 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
- netnode.o netport.o exports.o \
+ netnode.o netport.o pkey.o exports.o \
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 22cdafc..81c0f06 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -91,6 +91,7 @@
#include "netif.h"
#include "netnode.h"
#include "netport.h"
+#include "pkey.h"
#include "xfrm.h"
#include "netlabel.h"
#include "audit.h"
@@ -168,6 +169,7 @@ static int selinux_cache_avc_callback(u32 event)
sel_netnode_flush();
sel_netport_flush();
synchronize_net();
+ sel_pkey_flush();
security_infiniband_flush();
}
return 0;
@@ -5945,7 +5947,7 @@ static int selinux_pkey_access(u64 subnet_prefix, u16 pkey_val, void *security)
struct infiniband_security_struct *sec = security;
struct lsm_pkey_audit pkey;
- err = security_pkey_sid(subnet_prefix, pkey_val, &sid);
+ err = sel_pkey_sid(subnet_prefix, pkey_val, &sid);
if (err)
goto out;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 4e36976..21779b6 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -135,6 +135,12 @@ struct infiniband_security_struct {
u32 sid; /* SID of the queue pair or MAD agent */
};
+struct pkey_security_struct {
+ u64 subnet_prefix; /* Port subnet prefix */
+ u16 pkey; /* PKey number */
+ u32 sid; /* SID of pkey */
+};
+
extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/include/pkey.h b/security/selinux/include/pkey.h
new file mode 100644
index 0000000..b298ed4
--- /dev/null
+++ b/security/selinux/include/pkey.h
@@ -0,0 +1,33 @@
+/*
+ * pkey table
+ *
+ * SELinux must keep a mapping of pkeys to labels/SIDs. This
+ * mapping is maintained as part of the normal policy but a fast cache is
+ * needed to reduce the lookup overhead.
+ *
+ * Author: Dan Jurgens <danielj@mellanox.com>
+ *
+ */
+
+/*
+ * (c) Mellanox Technologies, 2016
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#ifndef _SELINUX_IB_H
+#define _SELINUX_IB_H
+
+void sel_pkey_flush(void);
+
+int sel_pkey_sid(u64 subnet_prefix, u16 pkey, u32 *sid);
+
+#endif
diff --git a/security/selinux/pkey.c b/security/selinux/pkey.c
new file mode 100644
index 0000000..bfb1f9c
--- /dev/null
+++ b/security/selinux/pkey.c
@@ -0,0 +1,220 @@
+/*
+ * Pkey table
+ *
+ * SELinux must keep a mapping of Infinband PKEYs to labels/SIDs. This
+ * mapping is maintained as part of the normal policy but a fast cache is
+ * needed to reduce the lookup overhead.
+ *
+ * Author: Daniel Jurgens <danielj@mellanox.com>
+ *
+ * This code is heavily based on the "netif" and "netport" concept originally
+ * developed by
+ * James Morris <jmorris@redhat.com> and
+ * Paul Moore <paul@paul-moore.com>
+ * (see security/selinux/netif.c and security/selinux/netport.c for more
+ * information)
+ *
+ */
+
+/*
+ * (c) Mellanox Technologies, 2016
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include "pkey.h"
+#include "objsec.h"
+
+#define SEL_PKEY_HASH_SIZE 256
+#define SEL_PKEY_HASH_BKT_LIMIT 16
+
+struct sel_pkey_bkt {
+ int size;
+ struct list_head list;
+};
+
+struct sel_pkey {
+ struct pkey_security_struct psec;
+ struct list_head list;
+ struct rcu_head rcu;
+};
+
+static LIST_HEAD(sel_pkey_list);
+static DEFINE_SPINLOCK(sel_pkey_lock);
+static struct sel_pkey_bkt sel_pkey_hash[SEL_PKEY_HASH_SIZE];
+
+/**
+ * sel_pkey_hashfn - Hashing function for the pkey table
+ * @pkey: pkey number
+ *
+ * Description:
+ * This is the hashing function for the pkey table, it returns the bucket
+ * number for the given pkey.
+ *
+ */
+static unsigned int sel_pkey_hashfn(u16 pkey)
+{
+ return (pkey & (SEL_PKEY_HASH_SIZE - 1));
+}
+
+/**
+ * sel_pkey_insert - Insert a new pkey into the table
+ * @pkey: the new pkey record
+ *
+ * Description:
+ * Add a new pkey record to the hash table.
+ *
+ */
+static void sel_pkey_insert(struct sel_pkey *pkey)
+{
+ unsigned int idx;
+
+ /* we need to impose a limit on the growth of the hash table so check
+ * this bucket to make sure it is within the specified bounds
+ */
+ idx = sel_pkey_hashfn(pkey->psec.pkey);
+ list_add_rcu(&pkey->list, &sel_pkey_hash[idx].list);
+ if (sel_pkey_hash[idx].size == SEL_PKEY_HASH_BKT_LIMIT) {
+ struct sel_pkey *tail;
+
+ tail = list_entry(
+ rcu_dereference_protected(
+ sel_pkey_hash[idx].list.prev,
+ lockdep_is_held(&sel_pkey_lock)),
+ struct sel_pkey, list);
+ list_del_rcu(&tail->list);
+ kfree_rcu(tail, rcu);
+ } else {
+ sel_pkey_hash[idx].size++;
+ }
+}
+
+/**
+ * sel_pkey_sid_slow - Lookup the SID of a pkey using the policy
+ * @subnet_prefix: subnet prefix
+ * @pkey_num: pkey number
+ * @sid: pkey SID
+ *
+ * Description:
+ * This function determines the SID of a pkey by querying the security
+ * policy. The result is added to the pkey table to speedup future
+ * queries. Returns zero on success, negative values on failure.
+ *
+ */
+static int sel_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
+{
+ int ret = -ENOMEM;
+ struct sel_pkey *new = NULL;
+
+ spin_lock_bh(&sel_pkey_lock);
+ new = kzalloc(sizeof(*new), GFP_ATOMIC);
+ if (!new)
+ goto out;
+ ret = security_pkey_sid(subnet_prefix, pkey_num, sid);
+ if (ret != 0)
+ goto out;
+
+ new->psec.subnet_prefix = subnet_prefix;
+ new->psec.pkey = pkey_num;
+ new->psec.sid = *sid;
+ sel_pkey_insert(new);
+
+out:
+ spin_unlock_bh(&sel_pkey_lock);
+ if (unlikely(ret))
+ kfree(new);
+
+ return ret;
+}
+
+/**
+ * sel_pkey_sid - Lookup the SID of a PKEY
+ * @subnet_prefix: subnet_prefix
+ * @pkey_num: pkey number
+ * @sid: pkey SID
+ *
+ * Description:
+ * This function determines the SID of a PKEY using the fastest method
+ * possible. First the pkey table is queried, but if an entry can't be found
+ * then the policy is queried and the result is added to the table to speedup
+ * future queries. Returns zero on success, negative values on failure.
+ *
+ */
+int sel_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *sid)
+{
+ struct sel_pkey *pkey, *found_pkey = NULL;
+ unsigned int idx;
+
+ rcu_read_lock();
+ idx = sel_pkey_hashfn(pkey_num);
+ list_for_each_entry_rcu(pkey, &sel_pkey_hash[idx].list, list) {
+ if (pkey->psec.pkey == pkey_num &&
+ pkey->psec.subnet_prefix == subnet_prefix) {
+ found_pkey = pkey;
+ break;
+ }
+ }
+
+ if (found_pkey) {
+ *sid = pkey->psec.sid;
+ rcu_read_unlock();
+ return 0;
+ }
+ rcu_read_unlock();
+
+ return sel_pkey_sid_slow(subnet_prefix, pkey_num, sid);
+}
+
+/**
+ * sel_pkey_flush - Flush the entire pkey table
+ *
+ * Description:
+ * Remove all entries from the pkey table
+ *
+ */
+void sel_pkey_flush(void)
+{
+ unsigned int idx;
+ struct sel_pkey *pkey, *pkey_tmp;
+
+ spin_lock_bh(&sel_pkey_lock);
+ for (idx = 0; idx < SEL_PKEY_HASH_SIZE; idx++) {
+ list_for_each_entry_safe(pkey, pkey_tmp,
+ &sel_pkey_hash[idx].list, list) {
+ list_del_rcu(&pkey->list);
+ kfree_rcu(pkey, rcu);
+ }
+ sel_pkey_hash[idx].size = 0;
+ }
+ spin_unlock_bh(&sel_pkey_lock);
+}
+
+static __init int sel_pkey_init(void)
+{
+ int iter;
+
+ if (!selinux_enabled)
+ return 0;
+
+ for (iter = 0; iter < SEL_PKEY_HASH_SIZE; iter++) {
+ INIT_LIST_HEAD(&sel_pkey_hash[iter].list);
+ sel_pkey_hash[iter].size = 0;
+ }
+
+ return 0;
+}
+
+subsys_initcall(sel_pkey_init);
--
1.7.1
prev parent reply other threads:[~2016-04-04 21:48 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-04 21:48 [RFC PATCH 0/7] SELinux support for Infiniband RDMA Dan Jurgens
2016-04-04 21:48 ` [RFC PATCH 1/7] security: Add LSM hooks for Infiniband security Dan Jurgens
[not found] ` <1459806504-16135-2-git-send-email-danielj-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2016-04-04 22:52 ` Or Gerlitz
2016-04-04 23:48 ` Casey Schaufler
2016-04-05 1:38 ` Daniel Jurgens
[not found] ` <1459806504-16135-1-git-send-email-danielj-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
2016-04-04 21:48 ` [RFC PATCH 2/7] selinux: Create policydb version for Infiniband support Dan Jurgens
2016-04-04 21:48 ` [RFC PATCH 3/7] selinux: Call infiniband_flush LSM hook on AVC reset Dan Jurgens
2016-04-04 21:48 ` [RFC PATCH 4/7] selinux: Allocate and free infiniband security hooks Dan Jurgens
2016-04-05 1:12 ` [RFC PATCH 0/7] SELinux support for Infiniband RDMA James Morris
2016-04-05 1:31 ` Daniel Jurgens
[not found] ` <DB5PR05MB111126C8AB59CDA4674A068BC49E0-8IvNv+8VlcBJTpKhoUy7I9qRiQSDpxhJvxpqHgZTriW3zl9H0oFU5g@public.gmane.org>
2016-04-05 1:55 ` James Morris
2016-04-05 14:04 ` Daniel Jurgens
2016-04-04 21:48 ` [RFC PATCH 5/7] selinux: Implement Infiniband PKey "Access" access vector Dan Jurgens
2016-04-04 21:48 ` [RFC PATCH 6/7] selinux: Implement IB Device SMI " Dan Jurgens
2016-04-04 21:48 ` Dan Jurgens [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1459806504-16135-8-git-send-email-danielj@mellanox.com \
--to=danielj@mellanox.com \
--cc=linux-rdma@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=selinux@tycho.nsa.gov \
--cc=yevgenyp@mellanox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox