aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/services.c
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/selinux/ss/services.c
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/selinux/ss/services.c')
-rw-r--r--security/selinux/ss/services.c107
1 files changed, 66 insertions, 41 deletions
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}