aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/services.c
diff options
context:
space:
mode:
authorVenkat Yekkirala <vyekkirala@TrustedCS.com>2006-08-05 02:17:57 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:36 -0400
commit7420ed23a4f77480b5b7b3245e5da30dd24b7575 (patch)
tree016f5bb996c5eae66754b10243c5be6226d773f2 /security/selinux/ss/services.c
parent96cb8e3313c7a12e026c1ed510522ae6f6023875 (diff)
[NetLabel]: SELinux support
Add NetLabel support to the SELinux LSM and modify the socket_post_create() LSM hook to return an error code. The most significant part of this patch is the addition of NetLabel hooks into the following SELinux LSM hooks: * selinux_file_permission() * selinux_socket_sendmsg() * selinux_socket_post_create() * selinux_socket_sock_rcv_skb() * selinux_socket_getpeersec_stream() * selinux_socket_getpeersec_dgram() * selinux_sock_graft() * selinux_inet_conn_request() The basic reasoning behind this patch is that outgoing packets are "NetLabel'd" by labeling their socket and the NetLabel security attributes are checked via the additional hook in selinux_socket_sock_rcv_skb(). NetLabel itself is only a labeling mechanism, similar to filesystem extended attributes, it is up to the SELinux enforcement mechanism to perform the actual access checks. In addition to the changes outlined above this patch also includes some changes to the extended bitmap (ebitmap) and multi-level security (mls) code to import and export SELinux TE/MLS attributes into and out of NetLabel. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r--security/selinux/ss/services.c488
1 files changed, 488 insertions, 0 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index b00ec69f0ffd..910afa1ffc31 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -13,6 +13,11 @@
13 * 13 *
14 * Added conditional policy language extensions 14 * Added conditional policy language extensions
15 * 15 *
16 * Updated: Hewlett-Packard <paul.moore@hp.com>
17 *
18 * Added support for NetLabel
19 *
20 * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
16 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 21 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
17 * Copyright (C) 2003 - 2004 Tresys Technology, LLC 22 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
18 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 23 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@@ -29,6 +34,8 @@
29#include <linux/sched.h> 34#include <linux/sched.h>
30#include <linux/audit.h> 35#include <linux/audit.h>
31#include <linux/mutex.h> 36#include <linux/mutex.h>
37#include <net/sock.h>
38#include <net/netlabel.h>
32 39
33#include "flask.h" 40#include "flask.h"
34#include "avc.h" 41#include "avc.h"
@@ -40,6 +47,8 @@
40#include "services.h" 47#include "services.h"
41#include "conditional.h" 48#include "conditional.h"
42#include "mls.h" 49#include "mls.h"
50#include "objsec.h"
51#include "selinux_netlabel.h"
43 52
44extern void selnl_notify_policyload(u32 seqno); 53extern void selnl_notify_policyload(u32 seqno);
45unsigned int policydb_loaded_version; 54unsigned int policydb_loaded_version;
@@ -1241,6 +1250,7 @@ int security_load_policy(void *data, size_t len)
1241 selinux_complete_init(); 1250 selinux_complete_init();
1242 avc_ss_reset(seqno); 1251 avc_ss_reset(seqno);
1243 selnl_notify_policyload(seqno); 1252 selnl_notify_policyload(seqno);
1253 selinux_netlbl_cache_invalidate();
1244 return 0; 1254 return 0;
1245 } 1255 }
1246 1256
@@ -1295,6 +1305,7 @@ int security_load_policy(void *data, size_t len)
1295 1305
1296 avc_ss_reset(seqno); 1306 avc_ss_reset(seqno);
1297 selnl_notify_policyload(seqno); 1307 selnl_notify_policyload(seqno);
1308 selinux_netlbl_cache_invalidate();
1298 1309
1299 return 0; 1310 return 0;
1300 1311
@@ -2133,3 +2144,480 @@ void selinux_audit_set_callback(int (*callback)(void))
2133{ 2144{
2134 aurule_callback = callback; 2145 aurule_callback = callback;
2135} 2146}
2147
2148#ifdef CONFIG_NETLABEL
2149/*
2150 * This is the structure we store inside the NetLabel cache block.
2151 */
2152#define NETLBL_CACHE(x) ((struct netlbl_cache *)(x))
2153#define NETLBL_CACHE_T_NONE 0
2154#define NETLBL_CACHE_T_SID 1
2155#define NETLBL_CACHE_T_MLS 2
2156struct netlbl_cache {
2157 u32 type;
2158 union {
2159 u32 sid;
2160 struct mls_range mls_label;
2161 } data;
2162};
2163
2164/**
2165 * selinux_netlbl_cache_free - Free the NetLabel cached data
2166 * @data: the data to free
2167 *
2168 * Description:
2169 * This function is intended to be used as the free() callback inside the
2170 * netlbl_lsm_cache structure.
2171 *
2172 */
2173static void selinux_netlbl_cache_free(const void *data)
2174{
2175 struct netlbl_cache *cache = NETLBL_CACHE(data);
2176 switch (cache->type) {
2177 case NETLBL_CACHE_T_MLS:
2178 ebitmap_destroy(&cache->data.mls_label.level[0].cat);
2179 break;
2180 }
2181 kfree(data);
2182}
2183
2184/**
2185 * selinux_netlbl_cache_add - Add an entry to the NetLabel cache
2186 * @skb: the packet
2187 * @ctx: the SELinux context
2188 *
2189 * Description:
2190 * Attempt to cache the context in @ctx, which was derived from the packet in
2191 * @skb, in the NetLabel subsystem cache.
2192 *
2193 */
2194static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
2195{
2196 struct netlbl_cache *cache = NULL;
2197 struct netlbl_lsm_secattr secattr;
2198
2199 netlbl_secattr_init(&secattr);
2200
2201 cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
2202 if (cache == NULL)
2203 goto netlbl_cache_add_failure;
2204 secattr.cache.free = selinux_netlbl_cache_free;
2205 secattr.cache.data = (void *)cache;
2206
2207 cache->type = NETLBL_CACHE_T_MLS;
2208 if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
2209 &ctx->range.level[0].cat) != 0)
2210 goto netlbl_cache_add_failure;
2211 cache->data.mls_label.level[1].cat.highbit =
2212 cache->data.mls_label.level[0].cat.highbit;
2213 cache->data.mls_label.level[1].cat.node =
2214 cache->data.mls_label.level[0].cat.node;
2215 cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
2216 cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
2217
2218 if (netlbl_cache_add(skb, &secattr) != 0)
2219 goto netlbl_cache_add_failure;
2220
2221 return;
2222
2223netlbl_cache_add_failure:
2224 netlbl_secattr_destroy(&secattr, 1);
2225}
2226
2227/**
2228 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
2229 *
2230 * Description:
2231 * Invalidate the NetLabel security attribute mapping cache.
2232 *
2233 */
2234void selinux_netlbl_cache_invalidate(void)
2235{
2236 netlbl_cache_invalidate();
2237}
2238
2239/**
2240 * selinux_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
2241 * @skb: the network packet
2242 * @secattr: the NetLabel packet security attributes
2243 * @base_sid: the SELinux SID to use as a context for MLS only attributes
2244 * @sid: the SELinux SID
2245 *
2246 * Description:
2247 * Convert the given NetLabel packet security attributes in @secattr into a
2248 * SELinux SID. If the @secattr field does not contain a full SELinux
2249 * SID/context then use the context in @base_sid as the foundation. If @skb
2250 * is not NULL attempt to cache as much data as possibile. Returns zero on
2251 * success, negative values on failure.
2252 *
2253 */
2254static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
2255 struct netlbl_lsm_secattr *secattr,
2256 u32 base_sid,
2257 u32 *sid)
2258{
2259 int rc = -EIDRM;
2260 struct context *ctx;
2261 struct context ctx_new;
2262 struct netlbl_cache *cache;
2263
2264 POLICY_RDLOCK;
2265
2266 if (secattr->cache.data) {
2267 cache = NETLBL_CACHE(secattr->cache.data);
2268 switch (cache->type) {
2269 case NETLBL_CACHE_T_SID:
2270 *sid = cache->data.sid;
2271 rc = 0;
2272 break;
2273 case NETLBL_CACHE_T_MLS:
2274 ctx = sidtab_search(&sidtab, base_sid);
2275 if (ctx == NULL)
2276 goto netlbl_secattr_to_sid_return;
2277
2278 ctx_new.user = ctx->user;
2279 ctx_new.role = ctx->role;
2280 ctx_new.type = ctx->type;
2281 ctx_new.range.level[0].sens =
2282 cache->data.mls_label.level[0].sens;
2283 ctx_new.range.level[0].cat.highbit =
2284 cache->data.mls_label.level[0].cat.highbit;
2285 ctx_new.range.level[0].cat.node =
2286 cache->data.mls_label.level[0].cat.node;
2287 ctx_new.range.level[1].sens =
2288 cache->data.mls_label.level[1].sens;
2289 ctx_new.range.level[1].cat.highbit =
2290 cache->data.mls_label.level[1].cat.highbit;
2291 ctx_new.range.level[1].cat.node =
2292 cache->data.mls_label.level[1].cat.node;
2293
2294 rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
2295 break;
2296 default:
2297 goto netlbl_secattr_to_sid_return;
2298 }
2299 } else if (secattr->mls_lvl_vld) {
2300 ctx = sidtab_search(&sidtab, base_sid);
2301 if (ctx == NULL)
2302 goto netlbl_secattr_to_sid_return;
2303
2304 ctx_new.user = ctx->user;
2305 ctx_new.role = ctx->role;
2306 ctx_new.type = ctx->type;
2307 mls_import_lvl(&ctx_new, secattr->mls_lvl, secattr->mls_lvl);
2308 if (secattr->mls_cat) {
2309 if (mls_import_cat(&ctx_new,
2310 secattr->mls_cat,
2311 secattr->mls_cat_len,
2312 NULL,
2313 0) != 0)
2314 goto netlbl_secattr_to_sid_return;
2315 ctx_new.range.level[1].cat.highbit =
2316 ctx_new.range.level[0].cat.highbit;
2317 ctx_new.range.level[1].cat.node =
2318 ctx_new.range.level[0].cat.node;
2319 } else {
2320 ebitmap_init(&ctx_new.range.level[0].cat);
2321 ebitmap_init(&ctx_new.range.level[1].cat);
2322 }
2323 if (mls_context_isvalid(&policydb, &ctx_new) != 1)
2324 goto netlbl_secattr_to_sid_return_cleanup;
2325
2326 rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
2327 if (rc != 0)
2328 goto netlbl_secattr_to_sid_return_cleanup;
2329
2330 if (skb != NULL)
2331 selinux_netlbl_cache_add(skb, &ctx_new);
2332 ebitmap_destroy(&ctx_new.range.level[0].cat);
2333 } else {
2334 *sid = SECINITSID_UNLABELED;
2335 rc = 0;
2336 }
2337
2338netlbl_secattr_to_sid_return:
2339 POLICY_RDUNLOCK;
2340 return rc;
2341netlbl_secattr_to_sid_return_cleanup:
2342 ebitmap_destroy(&ctx_new.range.level[0].cat);
2343 goto netlbl_secattr_to_sid_return;
2344}
2345
2346/**
2347 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
2348 * @skb: the packet
2349 * @base_sid: the SELinux SID to use as a context for MLS only attributes
2350 * @sid: the SID
2351 *
2352 * Description:
2353 * Call the NetLabel mechanism to get the security attributes of the given
2354 * packet and use those attributes to determine the correct context/SID to
2355 * assign to the packet. Returns zero on success, negative values on failure.
2356 *
2357 */
2358static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
2359 u32 base_sid,
2360 u32 *sid)
2361{
2362 int rc;
2363 struct netlbl_lsm_secattr secattr;
2364
2365 netlbl_secattr_init(&secattr);
2366 rc = netlbl_skbuff_getattr(skb, &secattr);
2367 if (rc == 0)
2368 rc = selinux_netlbl_secattr_to_sid(skb,
2369 &secattr,
2370 base_sid,
2371 sid);
2372 netlbl_secattr_destroy(&secattr, 0);
2373
2374 return rc;
2375}
2376
2377/**
2378 * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
2379 * @sock: the socket to label
2380 * @sid: the SID to use
2381 *
2382 * Description:
2383 * Attempt to label a socket using the NetLabel mechanism using the given
2384 * SID. Returns zero values on success, negative values on failure.
2385 *
2386 */
2387static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
2388{
2389 int rc = -ENOENT;
2390 struct sk_security_struct *sksec = sock->sk->sk_security;
2391 struct netlbl_lsm_secattr secattr;
2392 struct context *ctx;
2393
2394 if (!ss_initialized)
2395 return 0;
2396
2397 POLICY_RDLOCK;
2398
2399 ctx = sidtab_search(&sidtab, sid);
2400 if (ctx == NULL)
2401 goto netlbl_socket_setsid_return;
2402
2403 netlbl_secattr_init(&secattr);
2404 secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
2405 GFP_ATOMIC);
2406 mls_export_lvl(ctx, &secattr.mls_lvl, NULL);
2407 secattr.mls_lvl_vld = 1;
2408 mls_export_cat(ctx,
2409 &secattr.mls_cat,
2410 &secattr.mls_cat_len,
2411 NULL,
2412 NULL);
2413
2414 rc = netlbl_socket_setattr(sock, &secattr);
2415 if (rc == 0)
2416 sksec->nlbl_state = NLBL_LABELED;
2417
2418 netlbl_secattr_destroy(&secattr, 0);
2419
2420netlbl_socket_setsid_return:
2421 POLICY_RDUNLOCK;
2422 return rc;
2423}
2424
2425/**
2426 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
2427 * @sock: the socket to label
2428 * @sock_family: the socket family
2429 * @sid: the SID to use
2430 *
2431 * Description:
2432 * Attempt to label a socket using the NetLabel mechanism using the given
2433 * SID. Returns zero values on success, negative values on failure.
2434 *
2435 */
2436int selinux_netlbl_socket_post_create(struct socket *sock,
2437 int sock_family,
2438 u32 sid)
2439{
2440 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
2441 struct sk_security_struct *sksec = sock->sk->sk_security;
2442
2443 if (sock_family != PF_INET)
2444 return 0;
2445
2446 sksec->sclass = isec->sclass;
2447 sksec->nlbl_state = NLBL_REQUIRE;
2448 return selinux_netlbl_socket_setsid(sock, sid);
2449}
2450
2451/**
2452 * selinux_netlbl_sock_graft - Netlabel the new socket
2453 * @sk: the new connection
2454 * @sock: the new socket
2455 *
2456 * Description:
2457 * The connection represented by @sk is being grafted onto @sock so set the
2458 * socket's NetLabel to match the SID of @sk.
2459 *
2460 */
2461void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
2462{
2463 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
2464 struct sk_security_struct *sksec = sk->sk_security;
2465
2466 if (sk->sk_family != PF_INET)
2467 return;
2468
2469 sksec->nlbl_state = NLBL_REQUIRE;
2470 sksec->peer_sid = sksec->sid;
2471 sksec->sclass = isec->sclass;
2472
2473 /* Try to set the NetLabel on the socket to save time later, if we fail
2474 * here we will pick up the pieces in later calls to
2475 * selinux_netlbl_inode_permission(). */
2476 selinux_netlbl_socket_setsid(sock, sksec->sid);
2477}
2478
2479/**
2480 * selinux_netlbl_inet_conn_request - Handle a new connection request
2481 * @skb: the packet
2482 * @sock_sid: the SID of the parent socket
2483 *
2484 * Description:
2485 * If present, use the security attributes of the packet in @skb and the
2486 * parent sock's SID to arrive at a SID for the new child sock. Returns the
2487 * SID of the connection or SECSID_NULL on failure.
2488 *
2489 */
2490u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid)
2491{
2492 int rc;
2493 u32 peer_sid;
2494
2495 rc = selinux_netlbl_skbuff_getsid(skb, sock_sid, &peer_sid);
2496 if (rc != 0)
2497 return SECSID_NULL;
2498
2499 if (peer_sid == SECINITSID_UNLABELED)
2500 return SECSID_NULL;
2501
2502 return peer_sid;
2503}
2504
2505/**
2506 * __selinux_netlbl_inode_permission - Label a socket using NetLabel
2507 * @inode: the file descriptor's inode
2508 * @mask: the permission mask
2509 *
2510 * Description:
2511 * Try to label a socket with the inode's SID using NetLabel. Returns zero on
2512 * success, negative values on failure.
2513 *
2514 */
2515int __selinux_netlbl_inode_permission(struct inode *inode, int mask)
2516{
2517 int rc;
2518 struct socket *sock = SOCKET_I(inode);
2519 struct sk_security_struct *sksec = sock->sk->sk_security;
2520
2521 lock_sock(sock->sk);
2522 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
2523 release_sock(sock->sk);
2524
2525 return rc;
2526}
2527
2528/**
2529 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
2530 * @sksec: the sock's sk_security_struct
2531 * @skb: the packet
2532 * @ad: the audit data
2533 *
2534 * Description:
2535 * Fetch the NetLabel security attributes from @skb and perform an access check
2536 * against the receiving socket. Returns zero on success, negative values on
2537 * error.
2538 *
2539 */
2540int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
2541 struct sk_buff *skb,
2542 struct avc_audit_data *ad)
2543{
2544 int rc;
2545 u32 netlbl_sid;
2546 u32 recv_perm;
2547
2548 rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid);
2549 if (rc != 0)
2550 return rc;
2551
2552 if (netlbl_sid == SECINITSID_UNLABELED)
2553 return 0;
2554
2555 switch (sksec->sclass) {
2556 case SECCLASS_UDP_SOCKET:
2557 recv_perm = UDP_SOCKET__RECV_MSG;
2558 break;
2559 case SECCLASS_TCP_SOCKET:
2560 recv_perm = TCP_SOCKET__RECV_MSG;
2561 break;
2562 default:
2563 recv_perm = RAWIP_SOCKET__RECV_MSG;
2564 }
2565
2566 rc = avc_has_perm(sksec->sid,
2567 netlbl_sid,
2568 sksec->sclass,
2569 recv_perm,
2570 ad);
2571 if (rc == 0)
2572 return 0;
2573
2574 netlbl_skbuff_err(skb, rc);
2575 return rc;
2576}
2577
2578/**
2579 * selinux_netlbl_socket_peersid - Return the peer SID of a connected socket
2580 * @sock: the socket
2581 *
2582 * Description:
2583 * Examine @sock to find the connected peer's SID. Returns the SID on success
2584 * or SECSID_NULL on error.
2585 *
2586 */
2587u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
2588{
2589 struct sk_security_struct *sksec = sock->sk->sk_security;
2590
2591 if (sksec->peer_sid == SECINITSID_UNLABELED)
2592 return SECSID_NULL;
2593
2594 return sksec->peer_sid;
2595}
2596
2597/**
2598 * selinux_netlbl_socket_getpeersec_dgram - Return the SID of a NetLabel packet
2599 * @skb: the packet
2600 *
2601 * Description:
2602 * Examine @skb to find the SID assigned to it by NetLabel. Returns the SID on
2603 * success, SECSID_NULL on error.
2604 *
2605 */
2606u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
2607{
2608 int peer_sid;
2609 struct sock *sk = skb->sk;
2610 struct inode_security_struct *isec;
2611
2612 if (sk == NULL || sk->sk_socket == NULL)
2613 return SECSID_NULL;
2614
2615 isec = SOCK_INODE(sk->sk_socket)->i_security;
2616 if (selinux_netlbl_skbuff_getsid(skb, isec->sid, &peer_sid) != 0)
2617 return SECSID_NULL;
2618 if (peer_sid == SECINITSID_UNLABELED)
2619 return SECSID_NULL;
2620
2621 return peer_sid;
2622}
2623#endif /* CONFIG_NETLABEL */