aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2006-11-17 17:38:53 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:24:13 -0500
commit9f2ad66509b182b399a5b03de487f45bde623524 (patch)
tree8376dc2db99a78c1b043644f019c4dc224187f16 /security
parent9bb5fd2b05cb4dba229e225536faa59eaadd837d (diff)
NetLabel: SELinux cleanups
This patch does a lot of cleanup in the SELinux NetLabel support code. A summary of the changes include: * Use RCU locking for the NetLabel state variable in the skk_security_struct instead of using the inode_security_struct mutex. * Remove unnecessary parameters in selinux_netlbl_socket_post_create(). * Rename selinux_netlbl_sk_clone_security() to selinux_netlbl_sk_security_clone() to better fit the other NetLabel sk_security functions. * Improvements to selinux_netlbl_inode_permission() to help reduce the cost of the common case. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/hooks.c10
-rw-r--r--security/selinux/include/objsec.h2
-rw-r--r--security/selinux/include/selinux_netlabel.h21
-rw-r--r--security/selinux/ss/services.c107
4 files changed, 86 insertions, 54 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0cf98740ddc6..975c0dfb5a11 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3140,9 +3140,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
3140 if (sock->sk) { 3140 if (sock->sk) {
3141 sksec = sock->sk->sk_security; 3141 sksec = sock->sk->sk_security;
3142 sksec->sid = isec->sid; 3142 sksec->sid = isec->sid;
3143 err = selinux_netlbl_socket_post_create(sock, 3143 err = selinux_netlbl_socket_post_create(sock);
3144 family,
3145 isec->sid);
3146 } 3144 }
3147 3145
3148 return err; 3146 return err;
@@ -3661,7 +3659,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
3661 newssec->sid = ssec->sid; 3659 newssec->sid = ssec->sid;
3662 newssec->peer_sid = ssec->peer_sid; 3660 newssec->peer_sid = ssec->peer_sid;
3663 3661
3664 selinux_netlbl_sk_clone_security(ssec, newssec); 3662 selinux_netlbl_sk_security_clone(ssec, newssec);
3665} 3663}
3666 3664
3667static void selinux_sk_getsecid(struct sock *sk, u32 *secid) 3665static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -3730,7 +3728,9 @@ static void selinux_inet_csk_clone(struct sock *newsk,
3730 So we will wait until sock_graft to do it, by which 3728 So we will wait until sock_graft to do it, by which
3731 time it will have been created and available. */ 3729 time it will have been created and available. */
3732 3730
3733 selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family); 3731 /* We don't need to take any sort of lock here as we are the only
3732 * thread with access to newsksec */
3733 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
3734} 3734}
3735 3735
3736static void selinux_inet_conn_established(struct sock *sk, 3736static void selinux_inet_conn_established(struct sock *sk,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index ef2267fea8bd..91b88f0ba20c 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -23,6 +23,7 @@
23#include <linux/fs.h> 23#include <linux/fs.h>
24#include <linux/binfmts.h> 24#include <linux/binfmts.h>
25#include <linux/in.h> 25#include <linux/in.h>
26#include <linux/spinlock.h>
26#include "flask.h" 27#include "flask.h"
27#include "avc.h" 28#include "avc.h"
28 29
@@ -108,6 +109,7 @@ struct sk_security_struct {
108 NLBL_REQUIRE, 109 NLBL_REQUIRE,
109 NLBL_LABELED, 110 NLBL_LABELED,
110 } nlbl_state; 111 } nlbl_state;
112 spinlock_t nlbl_lock; /* protects nlbl_state */
111#endif 113#endif
112}; 114};
113 115
diff --git a/security/selinux/include/selinux_netlabel.h b/security/selinux/include/selinux_netlabel.h
index 9de10cc2cef2..57943f4a8f90 100644
--- a/security/selinux/include/selinux_netlabel.h
+++ b/security/selinux/include/selinux_netlabel.h
@@ -38,9 +38,7 @@
38 38
39#ifdef CONFIG_NETLABEL 39#ifdef CONFIG_NETLABEL
40void selinux_netlbl_cache_invalidate(void); 40void selinux_netlbl_cache_invalidate(void);
41int selinux_netlbl_socket_post_create(struct socket *sock, 41int selinux_netlbl_socket_post_create(struct socket *sock);
42 int sock_family,
43 u32 sid);
44void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); 42void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
45u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid); 43u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid);
46int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 44int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
@@ -48,9 +46,11 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
48 struct avc_audit_data *ad); 46 struct avc_audit_data *ad);
49u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock); 47u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock);
50u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb); 48u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb);
49void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
50 int family);
51void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, 51void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
52 int family); 52 int family);
53void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec, 53void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
54 struct sk_security_struct *newssec); 54 struct sk_security_struct *newssec);
55int selinux_netlbl_inode_permission(struct inode *inode, int mask); 55int selinux_netlbl_inode_permission(struct inode *inode, int mask);
56int selinux_netlbl_socket_setsockopt(struct socket *sock, 56int selinux_netlbl_socket_setsockopt(struct socket *sock,
@@ -62,9 +62,7 @@ static inline void selinux_netlbl_cache_invalidate(void)
62 return; 62 return;
63} 63}
64 64
65static inline int selinux_netlbl_socket_post_create(struct socket *sock, 65static inline int selinux_netlbl_socket_post_create(struct socket *sock)
66 int sock_family,
67 u32 sid)
68{ 66{
69 return 0; 67 return 0;
70} 68}
@@ -98,6 +96,13 @@ static inline u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
98 return SECSID_NULL; 96 return SECSID_NULL;
99} 97}
100 98
99static inline void selinux_netlbl_sk_security_reset(
100 struct sk_security_struct *ssec,
101 int family)
102{
103 return;
104}
105
101static inline void selinux_netlbl_sk_security_init( 106static inline void selinux_netlbl_sk_security_init(
102 struct sk_security_struct *ssec, 107 struct sk_security_struct *ssec,
103 int family) 108 int family)
@@ -105,7 +110,7 @@ static inline void selinux_netlbl_sk_security_init(
105 return; 110 return;
106} 111}
107 112
108static inline void selinux_netlbl_sk_clone_security( 113static inline void selinux_netlbl_sk_security_clone(
109 struct sk_security_struct *ssec, 114 struct sk_security_struct *ssec,
110 struct sk_security_struct *newssec) 115 struct sk_security_struct *newssec)
111{ 116{
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 1f5bbb246d28..b66b454fe72b 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -33,6 +33,7 @@
33#include <linux/slab.h> 33#include <linux/slab.h>
34#include <linux/string.h> 34#include <linux/string.h>
35#include <linux/spinlock.h> 35#include <linux/spinlock.h>
36#include <linux/rcupdate.h>
36#include <linux/errno.h> 37#include <linux/errno.h>
37#include <linux/in.h> 38#include <linux/in.h>
38#include <linux/sched.h> 39#include <linux/sched.h>
@@ -2435,7 +2436,9 @@ static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
2435 * 2436 *
2436 * Description: 2437 * Description:
2437 * Attempt to label a socket using the NetLabel mechanism using the given 2438 * Attempt to label a socket using the NetLabel mechanism using the given
2438 * SID. Returns zero values on success, negative values on failure. 2439 * SID. Returns zero values on success, negative values on failure. The
2440 * caller is responsibile for calling rcu_read_lock() before calling this
2441 * this function and rcu_read_unlock() after this function returns.
2439 * 2442 *
2440 */ 2443 */
2441static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid) 2444static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
@@ -2472,8 +2475,11 @@ static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
2472 secattr.flags |= NETLBL_SECATTR_MLS_CAT; 2475 secattr.flags |= NETLBL_SECATTR_MLS_CAT;
2473 2476
2474 rc = netlbl_socket_setattr(sock, &secattr); 2477 rc = netlbl_socket_setattr(sock, &secattr);
2475 if (rc == 0) 2478 if (rc == 0) {
2479 spin_lock(&sksec->nlbl_lock);
2476 sksec->nlbl_state = NLBL_LABELED; 2480 sksec->nlbl_state = NLBL_LABELED;
2481 spin_unlock(&sksec->nlbl_lock);
2482 }
2477 2483
2478netlbl_socket_setsid_return: 2484netlbl_socket_setsid_return:
2479 POLICY_RDUNLOCK; 2485 POLICY_RDUNLOCK;
@@ -2482,6 +2488,25 @@ netlbl_socket_setsid_return:
2482} 2488}
2483 2489
2484/** 2490/**
2491 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
2492 * @ssec: the sk_security_struct
2493 * @family: the socket family
2494 *
2495 * Description:
2496 * Called when the NetLabel state of a sk_security_struct needs to be reset.
2497 * The caller is responsibile for all the NetLabel sk_security_struct locking.
2498 *
2499 */
2500void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
2501 int family)
2502{
2503 if (family == PF_INET)
2504 ssec->nlbl_state = NLBL_REQUIRE;
2505 else
2506 ssec->nlbl_state = NLBL_UNSET;
2507}
2508
2509/**
2485 * selinux_netlbl_sk_security_init - Setup the NetLabel fields 2510 * selinux_netlbl_sk_security_init - Setup the NetLabel fields
2486 * @ssec: the sk_security_struct 2511 * @ssec: the sk_security_struct
2487 * @family: the socket family 2512 * @family: the socket family
@@ -2494,14 +2519,13 @@ netlbl_socket_setsid_return:
2494void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, 2519void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
2495 int family) 2520 int family)
2496{ 2521{
2497 if (family == PF_INET) 2522 /* No locking needed, we are the only one who has access to ssec */
2498 ssec->nlbl_state = NLBL_REQUIRE; 2523 selinux_netlbl_sk_security_reset(ssec, family);
2499 else 2524 spin_lock_init(&ssec->nlbl_lock);
2500 ssec->nlbl_state = NLBL_UNSET;
2501} 2525}
2502 2526
2503/** 2527/**
2504 * selinux_netlbl_sk_clone_security - Copy the NetLabel fields 2528 * selinux_netlbl_sk_security_clone - Copy the NetLabel fields
2505 * @ssec: the original sk_security_struct 2529 * @ssec: the original sk_security_struct
2506 * @newssec: the cloned sk_security_struct 2530 * @newssec: the cloned sk_security_struct
2507 * 2531 *
@@ -2510,41 +2534,41 @@ void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
2510 * @newssec. 2534 * @newssec.
2511 * 2535 *
2512 */ 2536 */
2513void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec, 2537void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
2514 struct sk_security_struct *newssec) 2538 struct sk_security_struct *newssec)
2515{ 2539{
2540 /* We don't need to take newssec->nlbl_lock because we are the only
2541 * thread with access to newssec, but we do need to take the RCU read
2542 * lock as other threads could have access to ssec */
2543 rcu_read_lock();
2544 selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
2516 newssec->sclass = ssec->sclass; 2545 newssec->sclass = ssec->sclass;
2517 if (ssec->nlbl_state != NLBL_UNSET) 2546 rcu_read_unlock();
2518 newssec->nlbl_state = NLBL_REQUIRE;
2519 else
2520 newssec->nlbl_state = NLBL_UNSET;
2521} 2547}
2522 2548
2523/** 2549/**
2524 * selinux_netlbl_socket_post_create - Label a socket using NetLabel 2550 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
2525 * @sock: the socket to label 2551 * @sock: the socket to label
2526 * @sock_family: the socket family
2527 * @sid: the SID to use
2528 * 2552 *
2529 * Description: 2553 * Description:
2530 * Attempt to label a socket using the NetLabel mechanism using the given 2554 * Attempt to label a socket using the NetLabel mechanism using the given
2531 * SID. Returns zero values on success, negative values on failure. 2555 * SID. Returns zero values on success, negative values on failure.
2532 * 2556 *
2533 */ 2557 */
2534int selinux_netlbl_socket_post_create(struct socket *sock, 2558int selinux_netlbl_socket_post_create(struct socket *sock)
2535 int sock_family,
2536 u32 sid)
2537{ 2559{
2560 int rc = 0;
2538 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; 2561 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
2539 struct sk_security_struct *sksec = sock->sk->sk_security; 2562 struct sk_security_struct *sksec = sock->sk->sk_security;
2540 2563
2541 sksec->sclass = isec->sclass; 2564 sksec->sclass = isec->sclass;
2542 2565
2543 if (sock_family != PF_INET) 2566 rcu_read_lock();
2544 return 0; 2567 if (sksec->nlbl_state == NLBL_REQUIRE)
2568 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
2569 rcu_read_unlock();
2545 2570
2546 sksec->nlbl_state = NLBL_REQUIRE; 2571 return rc;
2547 return selinux_netlbl_socket_setsid(sock, sid);
2548} 2572}
2549 2573
2550/** 2574/**
@@ -2566,8 +2590,12 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
2566 2590
2567 sksec->sclass = isec->sclass; 2591 sksec->sclass = isec->sclass;
2568 2592
2569 if (sk->sk_family != PF_INET) 2593 rcu_read_lock();
2594
2595 if (sksec->nlbl_state != NLBL_REQUIRE) {
2596 rcu_read_unlock();
2570 return; 2597 return;
2598 }
2571 2599
2572 netlbl_secattr_init(&secattr); 2600 netlbl_secattr_init(&secattr);
2573 if (netlbl_sock_getattr(sk, &secattr) == 0 && 2601 if (netlbl_sock_getattr(sk, &secattr) == 0 &&
@@ -2579,12 +2607,12 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
2579 sksec->peer_sid = nlbl_peer_sid; 2607 sksec->peer_sid = nlbl_peer_sid;
2580 netlbl_secattr_destroy(&secattr); 2608 netlbl_secattr_destroy(&secattr);
2581 2609
2582 sksec->nlbl_state = NLBL_REQUIRE;
2583
2584 /* Try to set the NetLabel on the socket to save time later, if we fail 2610 /* Try to set the NetLabel on the socket to save time later, if we fail
2585 * here we will pick up the pieces in later calls to 2611 * here we will pick up the pieces in later calls to
2586 * selinux_netlbl_inode_permission(). */ 2612 * selinux_netlbl_inode_permission(). */
2587 selinux_netlbl_socket_setsid(sock, sksec->sid); 2613 selinux_netlbl_socket_setsid(sock, sksec->sid);
2614
2615 rcu_read_unlock();
2588} 2616}
2589 2617
2590/** 2618/**
@@ -2625,25 +2653,24 @@ u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid)
2625int selinux_netlbl_inode_permission(struct inode *inode, int mask) 2653int selinux_netlbl_inode_permission(struct inode *inode, int mask)
2626{ 2654{
2627 int rc; 2655 int rc;
2628 struct inode_security_struct *isec;
2629 struct sk_security_struct *sksec; 2656 struct sk_security_struct *sksec;
2630 struct socket *sock; 2657 struct socket *sock;
2631 2658
2632 if (!S_ISSOCK(inode->i_mode)) 2659 if (!S_ISSOCK(inode->i_mode) ||
2660 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
2633 return 0; 2661 return 0;
2634
2635 sock = SOCKET_I(inode); 2662 sock = SOCKET_I(inode);
2636 isec = inode->i_security;
2637 sksec = sock->sk->sk_security; 2663 sksec = sock->sk->sk_security;
2638 mutex_lock(&isec->lock); 2664
2639 if (unlikely(sksec->nlbl_state == NLBL_REQUIRE && 2665 rcu_read_lock();
2640 (mask & (MAY_WRITE | MAY_APPEND)))) { 2666 if (sksec->nlbl_state != NLBL_REQUIRE) {
2641 lock_sock(sock->sk); 2667 rcu_read_unlock();
2642 rc = selinux_netlbl_socket_setsid(sock, sksec->sid); 2668 return 0;
2643 release_sock(sock->sk); 2669 }
2644 } else 2670 lock_sock(sock->sk);
2645 rc = 0; 2671 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
2646 mutex_unlock(&isec->lock); 2672 release_sock(sock->sk);
2673 rcu_read_unlock();
2647 2674
2648 return rc; 2675 return rc;
2649} 2676}
@@ -2754,12 +2781,10 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
2754 int optname) 2781 int optname)
2755{ 2782{
2756 int rc = 0; 2783 int rc = 0;
2757 struct inode *inode = SOCK_INODE(sock);
2758 struct sk_security_struct *sksec = sock->sk->sk_security; 2784 struct sk_security_struct *sksec = sock->sk->sk_security;
2759 struct inode_security_struct *isec = inode->i_security;
2760 struct netlbl_lsm_secattr secattr; 2785 struct netlbl_lsm_secattr secattr;
2761 2786
2762 mutex_lock(&isec->lock); 2787 rcu_read_lock();
2763 if (level == IPPROTO_IP && optname == IP_OPTIONS && 2788 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
2764 sksec->nlbl_state == NLBL_LABELED) { 2789 sksec->nlbl_state == NLBL_LABELED) {
2765 netlbl_secattr_init(&secattr); 2790 netlbl_secattr_init(&secattr);
@@ -2768,7 +2793,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
2768 rc = -EACCES; 2793 rc = -EACCES;
2769 netlbl_secattr_destroy(&secattr); 2794 netlbl_secattr_destroy(&secattr);
2770 } 2795 }
2771 mutex_unlock(&isec->lock); 2796 rcu_read_unlock();
2772 2797
2773 return rc; 2798 return rc;
2774} 2799}