Series short description
v3 cover Series short description
This revision includes the list_del_rcu() fix mentioned earlier this morning. This boots on a quasi-recent Rawhide machine (three/four days old?) with the targeted policy in enforcing mode with no noticeable regressions to networking: I can do a wget to google, SSH into the machine, ping, etc..
Signature · 7 lines
paul moore linux security @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
PATCH v3 1/2 SELinux: Made netnode cache adds faster
When adding new entries to the network node cache we would walk the entire hash bucket to make sure we didn't cross a threshold (done to bound the cache size). This isn't a very quick or elegant solution for something which is supposed to be quick-ish so add a counter to each hash bucket to track the size of the bucket and eliminate the need to walk the entire bucket list on each add.
---
security/selinux/netnode.c | 67 +++++++++++++++++++++----------------------- 1 files changed, 32 insertions(+), 35 deletions(-)
security/selinux/netnode.c +32 -35
@@ -40,11 +40,17 @@#include <net/ipv6.h> #include <asm/bug.h> +#include "netnode.h" #include "objsec.h" #define SEL_NETNODE_HASH_SIZE 256#define SEL_NETNODE_HASH_BKT_LIMIT 16 +struct sel_netnode_bkt { +unsigned int size; +struct list_head list; +}; +struct sel_netnode {struct netnode_security_struct nsec;
@@ -60,7 +66,7 @@ struct sel_netnode {static LIST_HEAD (sel_netnode_list);static DEFINE_SPINLOCK (sel_netnode_lock); -static struct list_head sel_netnode_hash[SEL_NETNODE_HASH_SIZE ]; +static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE ];/** * sel_netnode_free - Frees a node entry
@@ -87,7 +93,7 @@ static void sel_netnode_free(struct rcu_head *p)* the bucket number for the given IP address. * */ -static u32 sel_netnode_hashfn_ipv4 (__be32 addr) +static unsigned int sel_netnode_hashfn_ipv4 (__be32 addr) {/* at some point we should determine if the mismatch in byte order * affects the hash function dramatically */
@@ -103,7 +109,7 @@ static u32 sel_netnode_hashfn_ipv4(__be32 addr)* the bucket number for the given IP address. * */ -static u32 sel_netnode_hashfn_ipv6 (const struct in6_addr *addr) +static unsigned int sel_netnode_hashfn_ipv6 (const struct in6_addr *addr) {/* just hash the least significant 32 bits to keep things fast (they * are the most likely to be different anyway), we can revisit this
@@ -123,7 +129,7 @@ static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr)*/ static struct sel_netnode *sel_netnode_find (const void *addr,u16 family) { -u32 idx; +unsigned int idx;struct sel_netnode *node;switch (family) {
@@ -137,7 +143,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)BUG (); } -list_for_each_entry_rcu (node, &sel_netnode_hash[idx], list) +list_for_each_entry_rcu (node, &sel_netnode_hash[idx].list, list)if (node->nsec.family == family)switch (family) {case PF_INET :
@@ -165,9 +171,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)*/ static int sel_netnode_insert (struct sel_netnode *node) { -u32 idx; -u32 count =0 ; -struct sel_netnode *iter; +unsigned int idx;switch (node->nsec.family) {case PF_INET :
@@ -179,35 +183,22 @@ static int sel_netnode_insert(struct sel_netnode *node)default :BUG (); } -list_add_rcu (&node->list, &sel_netnode_hash[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 */ -list_for_each_entry (iter, &sel_netnode_hash[idx], list) -if (++count >SEL_NETNODE_HASH_BKT_LIMIT ) { -list_del_rcu (&iter->list); -call_rcu (&iter->rcu, sel_netnode_free); -break ; - } +list_add_rcu (&node->list, &sel_netnode_hash[idx].list); +if (sel_netnode_hash[idx].size ==SEL_NETNODE_HASH_BKT_LIMIT ) { +struct sel_netnode *tail; + tail = list_entry(node->list.prev, struct sel_netnode, list); +list_del_rcu (node->list.prev); +call_rcu (&tail->rcu, sel_netnode_free); + }else + sel_netnode_hash[idx].size++;return 0 ; }/** -* sel_netnode_destroy - Remove a node record from the table -* @node: the existing node record -* -* Description: -* Remove an existing node record from the network address table. -* -*/ -static void sel_netnode_destroy (struct sel_netnode *node) -{ -list_del_rcu (&node->list); -call_rcu (&node->rcu, sel_netnode_free); -} - -/** * sel_netnode_sid_slow - Lookup the SID of a network address using the policy * @addr: the IP address * @family: the address family
@@ -312,13 +303,17 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid)*/ static void sel_netnode_flush (void ) { -u32 idx; +unsigned int idx;struct sel_netnode *node;spin_lock_bh (&sel_netnode_lock); -for (idx =0 ; idx <SEL_NETNODE_HASH_SIZE ; idx++) -list_for_each_entry (node, &sel_netnode_hash[idx], list) -sel_netnode_destroy (node); +for (idx =0 ; idx <SEL_NETNODE_HASH_SIZE ; idx++) { +list_for_each_entry (node, &sel_netnode_hash[idx].list, list) { +list_del_rcu (&node->list); +call_rcu (&node->rcu, sel_netnode_free); + } + sel_netnode_hash[idx].size =0 ; + }spin_unlock_bh (&sel_netnode_lock); }
@@ -340,8 +335,10 @@ static __init int sel_netnode_init(void)if (!selinux_enabled)return 0 ; -for (iter =0 ; iter <SEL_NETNODE_HASH_SIZE ; iter++) -INIT_LIST_HEAD (&sel_netnode_hash[iter]); +for (iter =0 ; iter <SEL_NETNODE_HASH_SIZE ; iter++) { +INIT_LIST_HEAD (&sel_netnode_hash[iter].list); + sel_netnode_hash[iter].size =0 ; + } ret =avc_add_callback (sel_netnode_avc_callback,AVC_CALLBACK_RESET ,SECSID_NULL ,SECSID_NULL ,SECCLASS_NULL ,0 );
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH v3 1/2] SELinux: Made netnode cache adds faster
Quoted 8 lines · Paul Moore
When adding new entries to the network node cache we would walk the entire hash bucket to make sure we didn't cross a threshold (done to bound the cache size). This isn't a very quick or elegant solution for something which is supposed to be quick-ish so add a counter to each hash bucket to track the size of the bucket and eliminate the need to walk the entire bucket list on each add.
Signed-off-by Paul Moore <[email protected]>
Quoted 168 lines
---
security/selinux/netnode.c | 67 +++++++++++++++++++++----------------------- 1 files changed, 32 insertions(+), 35 deletions(-)security/selinux/netnode.c +32
-36@@ -40,11 +40,17 @@#include <net/ipv6.h> #include <asm/bug.h> +#include "netnode.h" #include "objsec.h" #define SEL_NETNODE_HASH_SIZE 256#define SEL_NETNODE_HASH_BKT_LIMIT 16 +struct sel_netnode_bkt { +unsigned int size; +struct list_head list; +}; +struct sel_netnode {struct netnode_security_struct nsec;@@ -60,7 +66,7 @@ struct sel_netnode {static LIST_HEAD (sel_netnode_list);static DEFINE_SPINLOCK (sel_netnode_lock); -static struct list_head sel_netnode_hash[SEL_NETNODE_HASH_SIZE ]; +static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE ];/** * sel_netnode_free - Frees a node entry @@ -87,7 +93,7 @@ static void sel_netnode_free(struct rcu_head *p)* the bucket number for the given IP address. * */ -static u32 sel_netnode_hashfn_ipv4 (__be32 addr) +static unsigned int sel_netnode_hashfn_ipv4 (__be32 addr) {/* at some point we should determine if the mismatch in byte order * affects the hash function dramatically */ @@ -103,7 +109,7 @@ static u32 sel_netnode_hashfn_ipv4(__be32 addr)* the bucket number for the given IP address. * */ -static u32 sel_netnode_hashfn_ipv6 (const struct in6_addr *addr) +static unsigned int sel_netnode_hashfn_ipv6 (const struct in6_addr *addr) {/* just hash the least significant 32 bits to keep things fast (they * are the most likely to be different anyway), we can revisit this @@ -123,7 +129,7 @@ static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr)*/ static struct sel_netnode *sel_netnode_find (const void *addr,u16 family) { -u32 idx; +unsigned int idx;struct sel_netnode *node;switch (family) {@@ -137,7 +143,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)BUG (); } -list_for_each_entry_rcu (node, &sel_netnode_hash[idx], list) +list_for_each_entry_rcu (node, &sel_netnode_hash[idx].list, list)if (node->nsec.family == family)switch (family) {case PF_INET :@@ -165,9 +171,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)*/ static int sel_netnode_insert (struct sel_netnode *node) { -u32 idx; -u32 count =0 ; -struct sel_netnode *iter; +unsigned int idx;switch (node->nsec.family) {case PF_INET :@@ -179,35 +183,22 @@ static int sel_netnode_insert(struct sel_netnode *node)default :BUG (); } -list_add_rcu (&node->list, &sel_netnode_hash[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 */ -list_for_each_entry (iter, &sel_netnode_hash[idx], list) -if (++count >SEL_NETNODE_HASH_BKT_LIMIT ) { -list_del_rcu (&iter->list); -call_rcu (&iter->rcu, sel_netnode_free); -break ; - } +list_add_rcu (&node->list, &sel_netnode_hash[idx].list); +if (sel_netnode_hash[idx].size ==SEL_NETNODE_HASH_BKT_LIMIT ) { +struct sel_netnode *tail; + tail = list_entry(node->list.prev, struct sel_netnode, list); +list_del_rcu (node->list.prev); +call_rcu (&tail->rcu, sel_netnode_free); + }else + sel_netnode_hash[idx].size++;return 0 ; }/** -* sel_netnode_destroy - Remove a node record from the table -* @node: the existing node record -* -* Description: -* Remove an existing node record from the network address table. -* -*/ -static void sel_netnode_destroy (struct sel_netnode *node) -{ -list_del_rcu (&node->list); -call_rcu (&node->rcu, sel_netnode_free); -} - -/** * sel_netnode_sid_slow - Lookup the SID of a network address using the policy * @addr: the IP address * @family: the address family @@ -312,13 +303,17 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid)*/ static void sel_netnode_flush (void ) { -u32 idx; +unsigned int idx;struct sel_netnode *node;spin_lock_bh (&sel_netnode_lock); -for (idx =0 ; idx <SEL_NETNODE_HASH_SIZE ; idx++) -list_for_each_entry (node, &sel_netnode_hash[idx], list) -sel_netnode_destroy (node); +for (idx =0 ; idx <SEL_NETNODE_HASH_SIZE ; idx++) { +list_for_each_entry (node, &sel_netnode_hash[idx].list, list) { +list_del_rcu (&node->list); +call_rcu (&node->rcu, sel_netnode_free); + } + sel_netnode_hash[idx].size =0 ; + }spin_unlock_bh (&sel_netnode_lock); }@@ -340,8 +335,10 @@ static __init int sel_netnode_init(void)if (!selinux_enabled)return 0 ; -for (iter =0 ; iter <SEL_NETNODE_HASH_SIZE ; iter++) -INIT_LIST_HEAD (&sel_netnode_hash[iter]); +for (iter =0 ; iter <SEL_NETNODE_HASH_SIZE ; iter++) { +INIT_LIST_HEAD (&sel_netnode_hash[iter].list); + sel_netnode_hash[iter].size =0 ; + } ret =avc_add_callback (sel_netnode_avc_callback,AVC_CALLBACK_RESET ,SECSID_NULL ,SECSID_NULL ,SECCLASS_NULL ,0 ); --This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
James Morris
AppliedRe: [PATCH v3 1/2] SELinux: Made netnode cache adds faster
Quoted 9 lines · Stephen Smalley
Quoted 7 lines · Paul Moore
When adding new entries to the network node cache we would walk the entire hash bucket to make sure we didn't cross a threshold (done to bound the cache size). This isn't a very quick or elegant solution for something which is supposed to be quick-ish so add a counter to each hash bucket to track the size of the bucket and eliminate the need to walk the entire bucket list on each add.
Quoted 3 lines
Quoted 1 line
Signed-off-by Paul Moore <[email protected]>Acked-by Stephen Smalley <[email protected]>
Applied to for-akpm.
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
PATCH v3 2/2 SELinux: Add network port SID cache
In reply to Paul MooreMuch like we added a network node cache, this patch adds a network port cache. The design is taken almost completely from the network node cache which in turn was taken from the network interface cache. The basic idea is to cache entries in a hash table based on protocol/port information. The hash function only takes the port number into account since the number of different protocols in use at any one time is expected to be relatively small.
---
security/selinux/Makefile | 1 security/selinux/hooks.c | 20 +- security/selinux/include/netport.h | 31 ++++ security/selinux/include/objsec.h | 6 + security/selinux/include/security.h | 3 security/selinux/netport.c | 286 +++++++++++++++++++++++++++++++++++ security/selinux/ss/services.c | 8 - 7 files changed, 334 insertions(+), 21 deletions(-)
security/selinux/Makefile +1 -0
@@ -11,6 +11,7 @@ selinux-y := avc.o \ nlmsgtab.o \ netif.o \ netnode.o \ + netport.o \ exports.o selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
security/selinux/hooks.c +8 -12
@@ -80,6 +80,7 @@#include "objsec.h" #include "netif.h" #include "netnode.h" +#include "netport.h" #include "xfrm.h" #include "netlabel.h"
@@ -3626,10 +3627,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, ininet_get_local_port_range (&low, &high);if (snum <max (PROT_SOCK , low) || snum > high) { - err =security_port_sid (sk->sk_family, - sk->sk_type, - sk->sk_protocol, snum, - &sid); + err =sel_netport_sid (sk->sk_protocol, + snum, &sid);if (err) goto out;AVC_AUDIT_DATA_INIT (&ad,NET );
@@ -3717,8 +3716,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, snum =ntohs (addr6->sin6_port); } - err =security_port_sid (sk->sk_family, sk->sk_type, - sk->sk_protocol, snum, &sid); + err =sel_netport_sid (sk->sk_protocol, snum, &sid);if (err) goto out;
@@ -3949,9 +3947,8 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,if (!recv_perm)return 0 ; - err =security_port_sid (sk->sk_family, sk->sk_type, - sk->sk_protocol,ntohs (ad->u.net.sport), - &port_sid); + err =sel_netport_sid (sk->sk_protocol, +ntohs (ad->u.net.sport), &port_sid);if (unlikely (err)) {printk (KERN_WARNING "SELinux: failure in"
@@ -4372,9 +4369,8 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,if (send_perm !=0 )return 0 ; - err =security_port_sid (sk->sk_family, sk->sk_type, - sk->sk_protocol,ntohs (ad->u.net.dport), - &port_sid); + err =sel_netport_sid (sk->sk_protocol, +ntohs (ad->u.net.dport), &port_sid);if (unlikely (err)) {printk (KERN_WARNING "SELinux: failure in"
security/selinux/include/netport.h new file +31 -0
@@ -0,0 +1,31 @@ +/* +* Network port table +* +* SELinux must keep a mapping of network ports 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: Paul Moore <[email protected]> +* +*/ + +/* +* (c) Copyright Hewlett-Packard Development Company, L.P., 2008 +* +* 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_NETPORT_H +#define _SELINUX_NETPORT_H + +int sel_netport_sid (u8 protocol,u16 pnum,u32 *sid); + +#endif
security/selinux/include/objsec.h +6 -0
@@ -109,6 +109,12 @@ struct netnode_security_struct {u16 family;/* address family */ }; +struct netport_security_struct { +u32 sid;/* SID for this node */ +u16 port;/* port number */ +u8 protocol;/* transport protocol */ +}; +struct sk_security_struct {struct sock *sk;/* back pointer to sk object */ u32 sid;/* SID of this object */
security/selinux/include/security.h +1 -2
@@ -91,8 +91,7 @@ int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *out_sint security_get_user_sids (u32 callsid,char *username,u32 **sids,u32 *nel); -int security_port_sid (u16 domain,u16 type,u8 protocol,u16 port, -u32 *out_sid); +int security_port_sid (u8 protocol,u16 port,u32 *out_sid);int security_netif_sid (char *name,u32 *if_sid);
security/selinux/netport.c new file +286 -0
286 lines not on this page · raw message
security/selinux/ss/services.c +1 -7
@@ -1441,17 +1441,11 @@ err:/** * security_port_sid - Obtain the SID for a port. -* @domain: communication domain aka address family -* @type: socket type * @protocol: protocol number * @port: port number * @out_sid: security identifier */ -int security_port_sid (u16 domain, -u16 type, -u8 protocol, -u16 port, -u32 *out_sid) +int security_port_sid (u8 protocol,u16 port,u32 *out_sid) {struct ocontext *c;int rc =0 ;
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH v3 2/2] SELinux: Add network port SID cache
Quoted 8 lines · Paul Moore
Much like we added a network node cache, this patch adds a network port cache. The design is taken almost completely from the network node cache which in turn was taken from the network interface cache. The basic idea is to cache entries in a hash table based on protocol/port information. The hash function only takes the port number into account since the number of different protocols in use at any one time is expected to be relatively small.
Signed-off-by Paul Moore <[email protected]>
Have you run any measurements with this added?
This should address:
https://bugzilla.redhat.com/show_bug.cgi?id=234531
http://marc.info/?l=linux-kernel&m=117499007102880&w=2
Quoted 471 lines
---
security/selinux/Makefile | 1 security/selinux/hooks.c | 20 +- security/selinux/include/netport.h | 31 ++++ security/selinux/include/objsec.h | 6 + security/selinux/include/security.h | 3 security/selinux/netport.c | 286 +++++++++++++++++++++++++++++++++++ security/selinux/ss/services.c | 8 - 7 files changed, 334 insertions(+), 21 deletions(-)security/selinux/Makefile +1
-0@@ -11,6 +11,7 @@ selinux-y := avc.o \ nlmsgtab.o \ netif.o \ netnode.o \ + netport.o \ exports.o selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.osecurity/selinux/hooks.c +8
-12@@ -80,6 +80,7 @@#include "objsec.h" #include "netif.h" #include "netnode.h" +#include "netport.h" #include "xfrm.h" #include "netlabel.h" @@ -3626,10 +3627,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, ininet_get_local_port_range (&low, &high);if (snum <max (PROT_SOCK , low) || snum > high) { - err =security_port_sid (sk->sk_family, - sk->sk_type, - sk->sk_protocol, snum, - &sid); + err =sel_netport_sid (sk->sk_protocol, + snum, &sid);if (err) goto out;AVC_AUDIT_DATA_INIT (&ad,NET );@@ -3717,8 +3716,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, snum =ntohs (addr6->sin6_port); } - err =security_port_sid (sk->sk_family, sk->sk_type, - sk->sk_protocol, snum, &sid); + err =sel_netport_sid (sk->sk_protocol, snum, &sid);if (err) goto out;@@ -3949,9 +3947,8 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,if (!recv_perm)return 0 ; - err =security_port_sid (sk->sk_family, sk->sk_type, - sk->sk_protocol,ntohs (ad->u.net.sport), - &port_sid); + err =sel_netport_sid (sk->sk_protocol, +ntohs (ad->u.net.sport), &port_sid);if (unlikely (err)) {printk (KERN_WARNING "SELinux: failure in"@@ -4372,9 +4369,8 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,if (send_perm !=0 )return 0 ; - err =security_port_sid (sk->sk_family, sk->sk_type, - sk->sk_protocol,ntohs (ad->u.net.dport), - &port_sid); + err =sel_netport_sid (sk->sk_protocol, +ntohs (ad->u.net.dport), &port_sid);if (unlikely (err)) {printk (KERN_WARNING "SELinux: failure in"security/selinux/include/netport.h new file +31
-0@@ -0,0 +1,31 @@ +/* +* Network port table +* +* SELinux must keep a mapping of network ports 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: Paul Moore <[email protected]> +* +*/ + +/* +* (c) Copyright Hewlett-Packard Development Company, L.P., 2008 +* +* 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_NETPORT_H +#define _SELINUX_NETPORT_H + +int sel_netport_sid (u8 protocol,u16 pnum,u32 *sid); + +#endif security/selinux/include/objsec.h +6
-0@@ -109,6 +109,12 @@ struct netnode_security_struct {u16 family;/* address family */ }; +struct netport_security_struct { +u32 sid;/* SID for this node */ +u16 port;/* port number */ +u8 protocol;/* transport protocol */ +}; +struct sk_security_struct {struct sock *sk;/* back pointer to sk object */ u32 sid;/* SID of this object */ security/selinux/include/security.h +1
-2@@ -91,8 +91,7 @@ int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *out_sint security_get_user_sids (u32 callsid,char *username,u32 **sids,u32 *nel); -int security_port_sid (u16 domain,u16 type,u8 protocol,u16 port, -u32 *out_sid); +int security_port_sid (u8 protocol,u16 port,u32 *out_sid);int security_netif_sid (char *name,u32 *if_sid);security/selinux/netport.c new file +286
-0@@ -0,0 +1,286 @@ +/* +* Network port table +* +* SELinux must keep a mapping of network ports 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: Paul Moore <[email protected]> +* +* This code is heavily based on the "netif" concept originally developed by +* James Morris <[email protected]> +* (see security/selinux/netif.c for more information) +* +*/ + +/* +* (c) Copyright Hewlett-Packard Development Company, L.P., 2008 +* +* 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 <linux/in.h> +#include <linux/in6.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <asm/bug.h> + +#include "netport.h" +#include "objsec.h" + +#define SEL_NETPORT_HASH_SIZE 256 +#define SEL_NETPORT_HASH_BKT_LIMIT 16 + +struct sel_netport_bkt { +int size; +struct list_head list; +}; + +struct sel_netport { +struct netport_security_struct psec; + +struct list_head list; +struct rcu_head rcu; +}; + +/* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason +* for this is that I suspect most users will not make heavy use of both +* address families at the same time so one table will usually end up wasted, +* if this becomes a problem we can always add a hash table for each address +* family later */ + +static LIST_HEAD (sel_netport_list); +static DEFINE_SPINLOCK (sel_netport_lock); +static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE ]; + +/** +* sel_netport_free - Frees a port entry +* @p: the entry's RCU field +* +* Description: +* This function is designed to be used as a callback to the call_rcu() +* function so that memory allocated to a hash table port entry can be +* released safely. +* +*/ +static void sel_netport_free (struct rcu_head *p) +{ + struct sel_netport *port = container_of(p, struct sel_netport, rcu); +kfree (port); +} + +/** +* sel_netport_hashfn - Hashing function for the port table +* @pnum: port number +* +* Description: +* This is the hashing function for the port table, it returns the bucket +* number for the given port. +* +*/ +static unsigned int sel_netport_hashfn (u16 pnum) +{ +return (pnum & (SEL_NETPORT_HASH_SIZE -1 )); +} + +/** +* sel_netport_find - Search for a port record +* @protocol: protocol +* @port: pnum +* +* Description: +* Search the network port table and return the matching record. If an entry +* can not be found in the table return NULL. +* +*/ +static struct sel_netport *sel_netport_find (u8 protocol,u16 pnum) +{ +unsigned int idx; +struct sel_netport *port; + + idx =sel_netport_hashfn (pnum); +list_for_each_entry_rcu (port, &sel_netport_hash[idx].list, list) +if (port->psec.port == pnum && + port->psec.protocol == protocol) +return port; + +return NULL ; +} + +/** +* sel_netport_insert - Insert a new port into the table +* @port: the new port record +* +* Description: +* Add a new port record to the network address hash table. Returns zero on +* success, negative values on failure. +* +*/ +static int sel_netport_insert (struct sel_netport *port) +{ +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_netport_hashfn (port->psec.port); +list_add_rcu (&port->list, &sel_netport_hash[idx].list); +if (sel_netport_hash[idx].size ==SEL_NETPORT_HASH_BKT_LIMIT ) { +struct sel_netport *tail; + tail = list_entry(port->list.prev, struct sel_netport, list); +list_del_rcu (port->list.prev); +call_rcu (&tail->rcu, sel_netport_free); + }else + sel_netport_hash[idx].size++; + +return 0 ; +} + +/** +* sel_netport_sid_slow - Lookup the SID of a network address using the policy +* @protocol: protocol +* @pnum: port +* @sid: port SID +* +* Description: +* This function determines the SID of a network port by quering the security +* policy. The result is added to the network port table to speedup future +* queries. Returns zero on success, negative values on failure. +* +*/ +static int sel_netport_sid_slow (u8 protocol,u16 pnum,u32 *sid) +{ +int ret; +struct sel_netport *port; +struct sel_netport *new =NULL ; + +spin_lock_bh (&sel_netport_lock); + port =sel_netport_find (protocol, pnum); +if (port !=NULL ) { + *sid = port->psec.sid; + ret =0 ; + goto out; + } + new =kzalloc (sizeof (*new),GFP_ATOMIC ); +if (new ==NULL ) { + ret = -ENOMEM ; + goto out; + } + ret =security_port_sid (protocol, pnum, &new->psec.sid); +if (ret !=0 ) + goto out; + new->psec.port = pnum; + new->psec.protocol = protocol; + ret =sel_netport_insert (new); +if (ret !=0 ) + goto out; + *sid = new->psec.sid; + +out: +spin_unlock_bh (&sel_netport_lock); +if (unlikely (ret)) { +printk (KERN_WARNING +"SELinux: failure in sel_netport_sid_slow()," +" unable to determine network port label\n" ); +kfree (new); + } +return ret; +} + +/** +* sel_netport_sid - Lookup the SID of a network port +* @protocol: protocol +* @pnum: port +* @sid: port SID +* +* Description: +* This function determines the SID of a network port using the fastest method +* possible. First the port 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_netport_sid (u8 protocol,u16 pnum,u32 *sid) +{ +struct sel_netport *port; + +rcu_read_lock (); + port =sel_netport_find (protocol, pnum); +if (port !=NULL ) { + *sid = port->psec.sid; +rcu_read_unlock (); +return 0 ; + } +rcu_read_unlock (); + +return sel_netport_sid_slow (protocol, pnum, sid); +} + +/** +* sel_netport_flush - Flush the entire network port table +* +* Description: +* Remove all entries from the network address table. +* +*/ +static void sel_netport_flush (void ) +{ +unsigned int idx; +struct sel_netport *port; + +spin_lock_bh (&sel_netport_lock); +for (idx =0 ; idx <SEL_NETPORT_HASH_SIZE ; idx++) { +list_for_each_entry (port, &sel_netport_hash[idx].list, list) { +list_del_rcu (&port->list); +call_rcu (&port->rcu, sel_netport_free); + } + sel_netport_hash[idx].size =0 ; + } +spin_unlock_bh (&sel_netport_lock); +} + +static int sel_netport_avc_callback (u32 event,u32 ssid,u32 tsid, +u16 class,u32 perms,u32 *retained) +{ +if (event ==AVC_CALLBACK_RESET ) { +sel_netport_flush (); +synchronize_net (); + } +return 0 ; +} + +static __init int sel_netport_init (void ) +{ +int iter; +int ret; + +if (!selinux_enabled) +return 0 ; + +for (iter =0 ; iter <SEL_NETPORT_HASH_SIZE ; iter++) { +INIT_LIST_HEAD (&sel_netport_hash[iter].list); + sel_netport_hash[iter].size =0 ; + } + + ret =avc_add_callback (sel_netport_avc_callback,AVC_CALLBACK_RESET , +SECSID_NULL ,SECSID_NULL ,SECCLASS_NULL ,0 ); +if (ret !=0 ) +panic ("avc_add_callback() failed, error %d\n" , ret); + +return ret; +} + +__initcall (sel_netport_init);security/selinux/ss/services.c +1
-8@@ -1441,17 +1441,11 @@ err:/** * security_port_sid - Obtain the SID for a port. -* @domain: communication domain aka address family -* @type: socket type * @protocol: protocol number * @port: port number * @out_sid: security identifier */ -int security_port_sid (u16 domain, -u16 type, -u8 protocol, -u16 port, -u32 *out_sid) +int security_port_sid (u8 protocol,u16 port,u32 *out_sid) {struct ocontext *c;int rc =0 ; --This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Re: [PATCH v3 2/2] SELinux: Add network port SID cache
Quoted 9 lines · Stephen Smalley
Quoted 8 lines · Paul Moore
Much like we added a network node cache, this patch adds a network port cache. The design is taken almost completely from the network node cache which in turn was taken from the network interface cache. The basic idea is to cache entries in a hash table based on protocol/port information. The hash function only takes the port number into account since the number of different protocols in use at any one time is expected to be relatively small.
Quoted 5 lines
Quoted 1 line
Signed-off-by Paul Moore <[email protected]>Acked-by Stephen Smalley <[email protected]>Have you run any measurements with this added?
Not at present.
Quoted 3 lines
This should address:
https://bugzilla.redhat.com/show_bug.cgi?id=234531
http://marc.info/?l=linux-kernel&m=117499007102880&w=2
Yep.
Signature · 7 lines
paul moore linux @ hp -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
James Morris
AppliedRe: [PATCH v3 2/2] SELinux: Add network port SID cache
In reply to Stephen SmalleyQuoted 9 lines · Stephen Smalley
Quoted 7 lines · Paul Moore
Much like we added a network node cache, this patch adds a network port cache. The design is taken almost completely from the network node cache which in turn was taken from the network interface cache. The basic idea is to cache entries in a hash table based on protocol/port information. The hash function only takes the port number into account since the number of different protocols in use at any one time is expected to be relatively small.
Quoted 3 lines
Quoted 1 line
Signed-off-by Paul Moore <[email protected]>Acked-by Stephen Smalley <[email protected]>
Applied to for-akpm.
Signature · 7 lines
James Morris <[email protected]> -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.