aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/services.c
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2007-02-28 15:14:22 -0500
committerJames Morris <jmorris@namei.org>2007-04-26 01:35:48 -0400
commit5778eabd9cdbf16ea3e40248c452b4fd25554d11 (patch)
treea488fd5fc07c01b93fe38621888cc50c64cfc0a1 /security/selinux/ss/services.c
parent128c6b6cbffc8203e13ea5712a8aa65d2ed82e4e (diff)
SELinux: extract the NetLabel SELinux support from the security server
Up until this patch the functions which have provided NetLabel support to SELinux have been integrated into the SELinux security server, which for various reasons is not really ideal. This patch makes an effort to extract as much of the NetLabel support from the security server as possibile and move it into it's own file within the SELinux directory structure. 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.c423
1 files changed, 58 insertions, 365 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 1e52356664d6..c8913c5dbe21 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2226,13 +2226,13 @@ void security_skb_extlbl_sid(struct sk_buff *skb, u32 base_sid, u32 *sid)
2226 2226
2227#ifdef CONFIG_NETLABEL 2227#ifdef CONFIG_NETLABEL
2228/* 2228/*
2229 * This is the structure we store inside the NetLabel cache block. 2229 * NetLabel cache structure
2230 */ 2230 */
2231#define NETLBL_CACHE(x) ((struct netlbl_cache *)(x)) 2231#define NETLBL_CACHE(x) ((struct selinux_netlbl_cache *)(x))
2232#define NETLBL_CACHE_T_NONE 0 2232#define NETLBL_CACHE_T_NONE 0
2233#define NETLBL_CACHE_T_SID 1 2233#define NETLBL_CACHE_T_SID 1
2234#define NETLBL_CACHE_T_MLS 2 2234#define NETLBL_CACHE_T_MLS 2
2235struct netlbl_cache { 2235struct selinux_netlbl_cache {
2236 u32 type; 2236 u32 type;
2237 union { 2237 union {
2238 u32 sid; 2238 u32 sid;
@@ -2241,7 +2241,7 @@ struct netlbl_cache {
2241}; 2241};
2242 2242
2243/** 2243/**
2244 * selinux_netlbl_cache_free - Free the NetLabel cached data 2244 * security_netlbl_cache_free - Free the NetLabel cached data
2245 * @data: the data to free 2245 * @data: the data to free
2246 * 2246 *
2247 * Description: 2247 * Description:
@@ -2249,9 +2249,9 @@ struct netlbl_cache {
2249 * netlbl_lsm_cache structure. 2249 * netlbl_lsm_cache structure.
2250 * 2250 *
2251 */ 2251 */
2252static void selinux_netlbl_cache_free(const void *data) 2252static void security_netlbl_cache_free(const void *data)
2253{ 2253{
2254 struct netlbl_cache *cache; 2254 struct selinux_netlbl_cache *cache;
2255 2255
2256 if (data == NULL) 2256 if (data == NULL)
2257 return; 2257 return;
@@ -2266,33 +2266,33 @@ static void selinux_netlbl_cache_free(const void *data)
2266} 2266}
2267 2267
2268/** 2268/**
2269 * selinux_netlbl_cache_add - Add an entry to the NetLabel cache 2269 * security_netlbl_cache_add - Add an entry to the NetLabel cache
2270 * @skb: the packet 2270 * @secattr: the NetLabel packet security attributes
2271 * @ctx: the SELinux context 2271 * @ctx: the SELinux context
2272 * 2272 *
2273 * Description: 2273 * Description:
2274 * Attempt to cache the context in @ctx, which was derived from the packet in 2274 * Attempt to cache the context in @ctx, which was derived from the packet in
2275 * @skb, in the NetLabel subsystem cache. 2275 * @skb, in the NetLabel subsystem cache. This function assumes @secattr has
2276 * already been initialized.
2276 * 2277 *
2277 */ 2278 */
2278static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx) 2279static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
2280 struct context *ctx)
2279{ 2281{
2280 struct netlbl_cache *cache = NULL; 2282 struct selinux_netlbl_cache *cache = NULL;
2281 struct netlbl_lsm_secattr secattr;
2282 2283
2283 netlbl_secattr_init(&secattr); 2284 secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
2284 secattr.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 2285 if (secattr->cache == NULL)
2285 if (secattr.cache == NULL) 2286 return;
2286 goto netlbl_cache_add_return;
2287 2287
2288 cache = kzalloc(sizeof(*cache), GFP_ATOMIC); 2288 cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
2289 if (cache == NULL) 2289 if (cache == NULL)
2290 goto netlbl_cache_add_return; 2290 return;
2291 2291
2292 cache->type = NETLBL_CACHE_T_MLS; 2292 cache->type = NETLBL_CACHE_T_MLS;
2293 if (ebitmap_cpy(&cache->data.mls_label.level[0].cat, 2293 if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
2294 &ctx->range.level[0].cat) != 0) 2294 &ctx->range.level[0].cat) != 0)
2295 goto netlbl_cache_add_return; 2295 return;
2296 cache->data.mls_label.level[1].cat.highbit = 2296 cache->data.mls_label.level[1].cat.highbit =
2297 cache->data.mls_label.level[0].cat.highbit; 2297 cache->data.mls_label.level[0].cat.highbit;
2298 cache->data.mls_label.level[1].cat.node = 2298 cache->data.mls_label.level[1].cat.node =
@@ -2300,52 +2300,40 @@ static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
2300 cache->data.mls_label.level[0].sens = ctx->range.level[0].sens; 2300 cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
2301 cache->data.mls_label.level[1].sens = ctx->range.level[0].sens; 2301 cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
2302 2302
2303 secattr.cache->free = selinux_netlbl_cache_free; 2303 secattr->cache->free = security_netlbl_cache_free;
2304 secattr.cache->data = (void *)cache; 2304 secattr->cache->data = (void *)cache;
2305 secattr.flags = NETLBL_SECATTR_CACHE; 2305 secattr->flags |= NETLBL_SECATTR_CACHE;
2306
2307 netlbl_cache_add(skb, &secattr);
2308
2309netlbl_cache_add_return:
2310 netlbl_secattr_destroy(&secattr);
2311} 2306}
2312 2307
2313/** 2308/**
2314 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 2309 * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
2315 *
2316 * Description:
2317 * Invalidate the NetLabel security attribute mapping cache.
2318 *
2319 */
2320void selinux_netlbl_cache_invalidate(void)
2321{
2322 netlbl_cache_invalidate();
2323}
2324
2325/**
2326 * selinux_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
2327 * @skb: the network packet
2328 * @secattr: the NetLabel packet security attributes 2310 * @secattr: the NetLabel packet security attributes
2329 * @base_sid: the SELinux SID to use as a context for MLS only attributes 2311 * @base_sid: the SELinux SID to use as a context for MLS only attributes
2330 * @sid: the SELinux SID 2312 * @sid: the SELinux SID
2331 * 2313 *
2332 * Description: 2314 * Description:
2333 * Convert the given NetLabel packet security attributes in @secattr into a 2315 * Convert the given NetLabel security attributes in @secattr into a
2334 * SELinux SID. If the @secattr field does not contain a full SELinux 2316 * SELinux SID. If the @secattr field does not contain a full SELinux
2335 * SID/context then use the context in @base_sid as the foundation. If @skb 2317 * SID/context then use the context in @base_sid as the foundation. If
2336 * is not NULL attempt to cache as much data as possibile. Returns zero on 2318 * possibile the 'cache' field of @secattr is set and the CACHE flag is set;
2337 * success, negative values on failure. 2319 * this is to allow the @secattr to be used by NetLabel to cache the secattr to
2320 * SID conversion for future lookups. Returns zero on success, negative
2321 * values on failure.
2338 * 2322 *
2339 */ 2323 */
2340static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb, 2324int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
2341 struct netlbl_lsm_secattr *secattr, 2325 u32 base_sid,
2342 u32 base_sid, 2326 u32 *sid)
2343 u32 *sid)
2344{ 2327{
2345 int rc = -EIDRM; 2328 int rc = -EIDRM;
2346 struct context *ctx; 2329 struct context *ctx;
2347 struct context ctx_new; 2330 struct context ctx_new;
2348 struct netlbl_cache *cache; 2331 struct selinux_netlbl_cache *cache;
2332
2333 if (!ss_initialized) {
2334 *sid = SECSID_NULL;
2335 return 0;
2336 }
2349 2337
2350 POLICY_RDLOCK; 2338 POLICY_RDLOCK;
2351 2339
@@ -2410,8 +2398,8 @@ static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
2410 if (rc != 0) 2398 if (rc != 0)
2411 goto netlbl_secattr_to_sid_return_cleanup; 2399 goto netlbl_secattr_to_sid_return_cleanup;
2412 2400
2413 if (skb != NULL) 2401 security_netlbl_cache_add(secattr, &ctx_new);
2414 selinux_netlbl_cache_add(skb, &ctx_new); 2402
2415 ebitmap_destroy(&ctx_new.range.level[0].cat); 2403 ebitmap_destroy(&ctx_new.range.level[0].cat);
2416 } else { 2404 } else {
2417 *sid = SECSID_NULL; 2405 *sid = SECSID_NULL;
@@ -2427,338 +2415,43 @@ netlbl_secattr_to_sid_return_cleanup:
2427} 2415}
2428 2416
2429/** 2417/**
2430 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel 2418 * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
2431 * @skb: the packet 2419 * @sid: the SELinux SID
2432 * @base_sid: the SELinux SID to use as a context for MLS only attributes 2420 * @secattr: the NetLabel packet security attributes
2433 * @sid: the SID
2434 *
2435 * Description:
2436 * Call the NetLabel mechanism to get the security attributes of the given
2437 * packet and use those attributes to determine the correct context/SID to
2438 * assign to the packet. Returns zero on success, negative values on failure.
2439 *
2440 */
2441int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
2442{
2443 int rc;
2444 struct netlbl_lsm_secattr secattr;
2445
2446 netlbl_secattr_init(&secattr);
2447 rc = netlbl_skbuff_getattr(skb, &secattr);
2448 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
2449 rc = selinux_netlbl_secattr_to_sid(skb,
2450 &secattr,
2451 base_sid,
2452 sid);
2453 else
2454 *sid = SECSID_NULL;
2455 netlbl_secattr_destroy(&secattr);
2456
2457 return rc;
2458}
2459
2460/**
2461 * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
2462 * @sock: the socket to label
2463 * @sid: the SID to use
2464 * 2421 *
2465 * Description: 2422 * Description:
2466 * Attempt to label a socket using the NetLabel mechanism using the given 2423 * Convert the given SELinux SID in @sid into a NetLabel security attribute.
2467 * SID. Returns zero values on success, negative values on failure. The 2424 * Returns zero on success, negative values on failure.
2468 * caller is responsibile for calling rcu_read_lock() before calling this
2469 * this function and rcu_read_unlock() after this function returns.
2470 * 2425 *
2471 */ 2426 */
2472static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid) 2427int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
2473{ 2428{
2474 int rc = -ENOENT; 2429 int rc = -ENOENT;
2475 struct sk_security_struct *sksec = sock->sk->sk_security;
2476 struct netlbl_lsm_secattr secattr;
2477 struct context *ctx; 2430 struct context *ctx;
2478 2431
2432 netlbl_secattr_init(secattr);
2433
2479 if (!ss_initialized) 2434 if (!ss_initialized)
2480 return 0; 2435 return 0;
2481 2436
2482 netlbl_secattr_init(&secattr);
2483
2484 POLICY_RDLOCK; 2437 POLICY_RDLOCK;
2485
2486 ctx = sidtab_search(&sidtab, sid); 2438 ctx = sidtab_search(&sidtab, sid);
2487 if (ctx == NULL) 2439 if (ctx == NULL)
2488 goto netlbl_socket_setsid_return; 2440 goto netlbl_sid_to_secattr_failure;
2489 2441 secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
2490 secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], 2442 GFP_ATOMIC);
2491 GFP_ATOMIC); 2443 secattr->flags |= NETLBL_SECATTR_DOMAIN;
2492 secattr.flags |= NETLBL_SECATTR_DOMAIN; 2444 mls_export_netlbl_lvl(ctx, secattr);
2493 mls_export_netlbl_lvl(ctx, &secattr); 2445 rc = mls_export_netlbl_cat(ctx, secattr);
2494 rc = mls_export_netlbl_cat(ctx, &secattr);
2495 if (rc != 0) 2446 if (rc != 0)
2496 goto netlbl_socket_setsid_return; 2447 goto netlbl_sid_to_secattr_failure;
2497
2498 rc = netlbl_socket_setattr(sock, &secattr);
2499 if (rc == 0) {
2500 spin_lock_bh(&sksec->nlbl_lock);
2501 sksec->nlbl_state = NLBL_LABELED;
2502 spin_unlock_bh(&sksec->nlbl_lock);
2503 }
2504
2505netlbl_socket_setsid_return:
2506 POLICY_RDUNLOCK; 2448 POLICY_RDUNLOCK;
2507 netlbl_secattr_destroy(&secattr);
2508 return rc;
2509}
2510
2511/**
2512 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
2513 * @ssec: the sk_security_struct
2514 * @family: the socket family
2515 *
2516 * Description:
2517 * Called when the NetLabel state of a sk_security_struct needs to be reset.
2518 * The caller is responsibile for all the NetLabel sk_security_struct locking.
2519 *
2520 */
2521void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
2522 int family)
2523{
2524 if (family == PF_INET)
2525 ssec->nlbl_state = NLBL_REQUIRE;
2526 else
2527 ssec->nlbl_state = NLBL_UNSET;
2528}
2529
2530/**
2531 * selinux_netlbl_sk_security_init - Setup the NetLabel fields
2532 * @ssec: the sk_security_struct
2533 * @family: the socket family
2534 *
2535 * Description:
2536 * Called when a new sk_security_struct is allocated to initialize the NetLabel
2537 * fields.
2538 *
2539 */
2540void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
2541 int family)
2542{
2543 /* No locking needed, we are the only one who has access to ssec */
2544 selinux_netlbl_sk_security_reset(ssec, family);
2545 spin_lock_init(&ssec->nlbl_lock);
2546}
2547 2449
2548/** 2450 return 0;
2549 * selinux_netlbl_sk_security_clone - Copy the NetLabel fields
2550 * @ssec: the original sk_security_struct
2551 * @newssec: the cloned sk_security_struct
2552 *
2553 * Description:
2554 * Clone the NetLabel specific sk_security_struct fields from @ssec to
2555 * @newssec.
2556 *
2557 */
2558void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
2559 struct sk_security_struct *newssec)
2560{
2561 /* We don't need to take newssec->nlbl_lock because we are the only
2562 * thread with access to newssec, but we do need to take the RCU read
2563 * lock as other threads could have access to ssec */
2564 rcu_read_lock();
2565 selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
2566 newssec->sclass = ssec->sclass;
2567 rcu_read_unlock();
2568}
2569
2570/**
2571 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
2572 * @sock: the socket to label
2573 *
2574 * Description:
2575 * Attempt to label a socket using the NetLabel mechanism using the given
2576 * SID. Returns zero values on success, negative values on failure.
2577 *
2578 */
2579int selinux_netlbl_socket_post_create(struct socket *sock)
2580{
2581 int rc = 0;
2582 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
2583 struct sk_security_struct *sksec = sock->sk->sk_security;
2584
2585 sksec->sclass = isec->sclass;
2586
2587 rcu_read_lock();
2588 if (sksec->nlbl_state == NLBL_REQUIRE)
2589 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
2590 rcu_read_unlock();
2591
2592 return rc;
2593}
2594
2595/**
2596 * selinux_netlbl_sock_graft - Netlabel the new socket
2597 * @sk: the new connection
2598 * @sock: the new socket
2599 *
2600 * Description:
2601 * The connection represented by @sk is being grafted onto @sock so set the
2602 * socket's NetLabel to match the SID of @sk.
2603 *
2604 */
2605void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
2606{
2607 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
2608 struct sk_security_struct *sksec = sk->sk_security;
2609 struct netlbl_lsm_secattr secattr;
2610 u32 nlbl_peer_sid;
2611
2612 sksec->sclass = isec->sclass;
2613
2614 rcu_read_lock();
2615
2616 if (sksec->nlbl_state != NLBL_REQUIRE) {
2617 rcu_read_unlock();
2618 return;
2619 }
2620
2621 netlbl_secattr_init(&secattr);
2622 if (netlbl_sock_getattr(sk, &secattr) == 0 &&
2623 secattr.flags != NETLBL_SECATTR_NONE &&
2624 selinux_netlbl_secattr_to_sid(NULL,
2625 &secattr,
2626 SECINITSID_UNLABELED,
2627 &nlbl_peer_sid) == 0)
2628 sksec->peer_sid = nlbl_peer_sid;
2629 netlbl_secattr_destroy(&secattr);
2630
2631 /* Try to set the NetLabel on the socket to save time later, if we fail
2632 * here we will pick up the pieces in later calls to
2633 * selinux_netlbl_inode_permission(). */
2634 selinux_netlbl_socket_setsid(sock, sksec->sid);
2635
2636 rcu_read_unlock();
2637}
2638
2639/**
2640 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
2641 * @inode: the file descriptor's inode
2642 * @mask: the permission mask
2643 *
2644 * Description:
2645 * Looks at a file's inode and if it is marked as a socket protected by
2646 * NetLabel then verify that the socket has been labeled, if not try to label
2647 * the socket now with the inode's SID. Returns zero on success, negative
2648 * values on failure.
2649 *
2650 */
2651int selinux_netlbl_inode_permission(struct inode *inode, int mask)
2652{
2653 int rc;
2654 struct sk_security_struct *sksec;
2655 struct socket *sock;
2656
2657 if (!S_ISSOCK(inode->i_mode) ||
2658 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
2659 return 0;
2660 sock = SOCKET_I(inode);
2661 sksec = sock->sk->sk_security;
2662
2663 rcu_read_lock();
2664 if (sksec->nlbl_state != NLBL_REQUIRE) {
2665 rcu_read_unlock();
2666 return 0;
2667 }
2668 local_bh_disable();
2669 bh_lock_sock_nested(sock->sk);
2670 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
2671 bh_unlock_sock(sock->sk);
2672 local_bh_enable();
2673 rcu_read_unlock();
2674
2675 return rc;
2676}
2677
2678/**
2679 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
2680 * @sksec: the sock's sk_security_struct
2681 * @skb: the packet
2682 * @ad: the audit data
2683 *
2684 * Description:
2685 * Fetch the NetLabel security attributes from @skb and perform an access check
2686 * against the receiving socket. Returns zero on success, negative values on
2687 * error.
2688 *
2689 */
2690int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
2691 struct sk_buff *skb,
2692 struct avc_audit_data *ad)
2693{
2694 int rc;
2695 u32 netlbl_sid;
2696 u32 recv_perm;
2697
2698 rc = selinux_netlbl_skbuff_getsid(skb,
2699 SECINITSID_UNLABELED,
2700 &netlbl_sid);
2701 if (rc != 0)
2702 return rc;
2703
2704 if (netlbl_sid == SECSID_NULL)
2705 return 0;
2706
2707 switch (sksec->sclass) {
2708 case SECCLASS_UDP_SOCKET:
2709 recv_perm = UDP_SOCKET__RECVFROM;
2710 break;
2711 case SECCLASS_TCP_SOCKET:
2712 recv_perm = TCP_SOCKET__RECVFROM;
2713 break;
2714 default:
2715 recv_perm = RAWIP_SOCKET__RECVFROM;
2716 }
2717
2718 rc = avc_has_perm(sksec->sid,
2719 netlbl_sid,
2720 sksec->sclass,
2721 recv_perm,
2722 ad);
2723 if (rc == 0)
2724 return 0;
2725
2726 netlbl_skbuff_err(skb, rc);
2727 return rc;
2728}
2729
2730/**
2731 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
2732 * @sock: the socket
2733 * @level: the socket level or protocol
2734 * @optname: the socket option name
2735 *
2736 * Description:
2737 * Check the setsockopt() call and if the user is trying to replace the IP
2738 * options on a socket and a NetLabel is in place for the socket deny the
2739 * access; otherwise allow the access. Returns zero when the access is
2740 * allowed, -EACCES when denied, and other negative values on error.
2741 *
2742 */
2743int selinux_netlbl_socket_setsockopt(struct socket *sock,
2744 int level,
2745 int optname)
2746{
2747 int rc = 0;
2748 struct sk_security_struct *sksec = sock->sk->sk_security;
2749 struct netlbl_lsm_secattr secattr;
2750
2751 rcu_read_lock();
2752 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
2753 sksec->nlbl_state == NLBL_LABELED) {
2754 netlbl_secattr_init(&secattr);
2755 rc = netlbl_socket_getattr(sock, &secattr);
2756 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
2757 rc = -EACCES;
2758 netlbl_secattr_destroy(&secattr);
2759 }
2760 rcu_read_unlock();
2761 2451
2452netlbl_sid_to_secattr_failure:
2453 POLICY_RDUNLOCK;
2454 netlbl_secattr_destroy(secattr);
2762 return rc; 2455 return rc;
2763} 2456}
2764#endif /* CONFIG_NETLABEL */ 2457#endif /* CONFIG_NETLABEL */