aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss
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
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')
-rw-r--r--security/selinux/ss/ebitmap.c144
-rw-r--r--security/selinux/ss/ebitmap.h6
-rw-r--r--security/selinux/ss/mls.c156
-rw-r--r--security/selinux/ss/mls.h21
-rw-r--r--security/selinux/ss/services.c488
5 files changed, 815 insertions, 0 deletions
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 47024a6e1844..4b915eb60c45 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -3,6 +3,14 @@
3 * 3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */ 5 */
6/*
7 * Updated: Hewlett-Packard <paul.moore@hp.com>
8 *
9 * Added ebitmap_export() and ebitmap_import()
10 *
11 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
12 */
13
6#include <linux/kernel.h> 14#include <linux/kernel.h>
7#include <linux/slab.h> 15#include <linux/slab.h>
8#include <linux/errno.h> 16#include <linux/errno.h>
@@ -59,6 +67,142 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
59 return 0; 67 return 0;
60} 68}
61 69
70/**
71 * ebitmap_export - Export an ebitmap to a unsigned char bitmap string
72 * @src: the ebitmap to export
73 * @dst: the resulting bitmap string
74 * @dst_len: length of dst in bytes
75 *
76 * Description:
77 * Allocate a buffer at least src->highbit bits long and export the extensible
78 * bitmap into the buffer. The bitmap string will be in little endian format,
79 * i.e. LSB first. The value returned in dst_len may not the true size of the
80 * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE.
81 * The caller must free the buffer when finished. Returns zero on success,
82 * negative values on failure.
83 *
84 */
85int ebitmap_export(const struct ebitmap *src,
86 unsigned char **dst,
87 size_t *dst_len)
88{
89 size_t bitmap_len;
90 unsigned char *bitmap;
91 struct ebitmap_node *iter_node;
92 MAPTYPE node_val;
93 size_t bitmap_byte;
94 unsigned char bitmask;
95
96 bitmap_len = src->highbit / 8;
97 if (src->highbit % 7)
98 bitmap_len += 1;
99 if (bitmap_len == 0)
100 return -EINVAL;
101
102 bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) +
103 sizeof(MAPTYPE),
104 GFP_ATOMIC);
105 if (bitmap == NULL)
106 return -ENOMEM;
107
108 iter_node = src->node;
109 do {
110 bitmap_byte = iter_node->startbit / 8;
111 bitmask = 0x80;
112 node_val = iter_node->map;
113 do {
114 if (bitmask == 0) {
115 bitmap_byte++;
116 bitmask = 0x80;
117 }
118 if (node_val & (MAPTYPE)0x01)
119 bitmap[bitmap_byte] |= bitmask;
120 node_val >>= 1;
121 bitmask >>= 1;
122 } while (node_val > 0);
123 iter_node = iter_node->next;
124 } while (iter_node);
125
126 *dst = bitmap;
127 *dst_len = bitmap_len;
128 return 0;
129}
130
131/**
132 * ebitmap_import - Import an unsigned char bitmap string into an ebitmap
133 * @src: the bitmap string
134 * @src_len: the bitmap length in bytes
135 * @dst: the empty ebitmap
136 *
137 * Description:
138 * This function takes a little endian bitmap string in src and imports it into
139 * the ebitmap pointed to by dst. Returns zero on success, negative values on
140 * failure.
141 *
142 */
143int ebitmap_import(const unsigned char *src,
144 size_t src_len,
145 struct ebitmap *dst)
146{
147 size_t src_off = 0;
148 struct ebitmap_node *node_new;
149 struct ebitmap_node *node_last = NULL;
150 size_t iter;
151 size_t iter_bit;
152 size_t iter_limit;
153 unsigned char src_byte;
154
155 do {
156 iter_limit = src_len - src_off;
157 if (iter_limit >= sizeof(MAPTYPE)) {
158 if (*(MAPTYPE *)&src[src_off] == 0) {
159 src_off += sizeof(MAPTYPE);
160 continue;
161 }
162 iter_limit = sizeof(MAPTYPE);
163 } else {
164 iter = src_off;
165 src_byte = 0;
166 do {
167 src_byte |= src[iter++];
168 } while (iter < src_len && src_byte == 0);
169 if (src_byte == 0)
170 break;
171 }
172
173 node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC);
174 if (unlikely(node_new == NULL)) {
175 ebitmap_destroy(dst);
176 return -ENOMEM;
177 }
178 node_new->startbit = src_off * 8;
179 iter = 0;
180 do {
181 src_byte = src[src_off++];
182 iter_bit = iter++ * 8;
183 while (src_byte != 0) {
184 if (src_byte & 0x80)
185 node_new->map |= MAPBIT << iter_bit;
186 iter_bit++;
187 src_byte <<= 1;
188 }
189 } while (iter < iter_limit);
190
191 if (node_last != NULL)
192 node_last->next = node_new;
193 else
194 dst->node = node_new;
195 node_last = node_new;
196 } while (src_off < src_len);
197
198 if (likely(node_last != NULL))
199 dst->highbit = node_last->startbit + MAPSIZE;
200 else
201 ebitmap_init(dst);
202
203 return 0;
204}
205
62int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) 206int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
63{ 207{
64 struct ebitmap_node *n1, *n2; 208 struct ebitmap_node *n1, *n2;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 8bf41055a6cb..da2d4651b10d 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -69,6 +69,12 @@ static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
69 69
70int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); 70int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
71int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); 71int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
72int ebitmap_export(const struct ebitmap *src,
73 unsigned char **dst,
74 size_t *dst_len);
75int ebitmap_import(const unsigned char *src,
76 size_t src_len,
77 struct ebitmap *dst);
72int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); 78int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
73int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); 79int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
74int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); 80int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index e15f7e0399b8..119bd6078ba1 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -10,6 +10,13 @@
10 * 10 *
11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12 */ 12 */
13/*
14 * Updated: Hewlett-Packard <paul.moore@hp.com>
15 *
16 * Added support to import/export the MLS label
17 *
18 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
19 */
13 20
14#include <linux/kernel.h> 21#include <linux/kernel.h>
15#include <linux/slab.h> 22#include <linux/slab.h>
@@ -565,3 +572,152 @@ int mls_compute_sid(struct context *scontext,
565 return -EINVAL; 572 return -EINVAL;
566} 573}
567 574
575/**
576 * mls_export_lvl - Export the MLS sensitivity levels
577 * @context: the security context
578 * @low: the low sensitivity level
579 * @high: the high sensitivity level
580 *
581 * Description:
582 * Given the security context copy the low MLS sensitivity level into lvl_low
583 * and the high sensitivity level in lvl_high. The MLS levels are only
584 * exported if the pointers are not NULL, if they are NULL then that level is
585 * not exported.
586 *
587 */
588void mls_export_lvl(const struct context *context, u32 *low, u32 *high)
589{
590 if (!selinux_mls_enabled)
591 return;
592
593 if (low != NULL)
594 *low = context->range.level[0].sens - 1;
595 if (high != NULL)
596 *high = context->range.level[1].sens - 1;
597}
598
599/**
600 * mls_import_lvl - Import the MLS sensitivity levels
601 * @context: the security context
602 * @low: the low sensitivity level
603 * @high: the high sensitivity level
604 *
605 * Description:
606 * Given the security context and the two sensitivty levels, set the MLS levels
607 * in the context according the two given as parameters. Returns zero on
608 * success, negative values on failure.
609 *
610 */
611void mls_import_lvl(struct context *context, u32 low, u32 high)
612{
613 if (!selinux_mls_enabled)
614 return;
615
616 context->range.level[0].sens = low + 1;
617 context->range.level[1].sens = high + 1;
618}
619
620/**
621 * mls_export_cat - Export the MLS categories
622 * @context: the security context
623 * @low: the low category
624 * @low_len: length of the cat_low bitmap in bytes
625 * @high: the high category
626 * @high_len: length of the cat_high bitmap in bytes
627 *
628 * Description:
629 * Given the security context export the low MLS category bitmap into cat_low
630 * and the high category bitmap into cat_high. The MLS categories are only
631 * exported if the pointers are not NULL, if they are NULL then that level is
632 * not exported. The caller is responsibile for freeing the memory when
633 * finished. Returns zero on success, negative values on failure.
634 *
635 */
636int mls_export_cat(const struct context *context,
637 unsigned char **low,
638 size_t *low_len,
639 unsigned char **high,
640 size_t *high_len)
641{
642 int rc = -EPERM;
643
644 if (!selinux_mls_enabled)
645 return 0;
646
647 if (low != NULL) {
648 rc = ebitmap_export(&context->range.level[0].cat,
649 low,
650 low_len);
651 if (rc != 0)
652 goto export_cat_failure;
653 }
654 if (high != NULL) {
655 rc = ebitmap_export(&context->range.level[1].cat,
656 high,
657 high_len);
658 if (rc != 0)
659 goto export_cat_failure;
660 }
661
662 return 0;
663
664export_cat_failure:
665 if (low != NULL)
666 kfree(*low);
667 if (high != NULL)
668 kfree(*high);
669 return rc;
670}
671
672/**
673 * mls_import_cat - Import the MLS categories
674 * @context: the security context
675 * @low: the low category
676 * @low_len: length of the cat_low bitmap in bytes
677 * @high: the high category
678 * @high_len: length of the cat_high bitmap in bytes
679 *
680 * Description:
681 * Given the security context and the two category bitmap strings import the
682 * categories into the security context. The MLS categories are only imported
683 * if the pointers are not NULL, if they are NULL they are skipped. Returns
684 * zero on success, negative values on failure.
685 *
686 */
687int mls_import_cat(struct context *context,
688 const unsigned char *low,
689 size_t low_len,
690 const unsigned char *high,
691 size_t high_len)
692{
693 int rc = -EPERM;
694
695 if (!selinux_mls_enabled)
696 return 0;
697
698 if (low != NULL) {
699 rc = ebitmap_import(low,
700 low_len,
701 &context->range.level[0].cat);
702 if (rc != 0)
703 goto import_cat_failure;
704 }
705 if (high != NULL) {
706 if (high == low)
707 rc = ebitmap_cpy(&context->range.level[1].cat,
708 &context->range.level[0].cat);
709 else
710 rc = ebitmap_import(high,
711 high_len,
712 &context->range.level[1].cat);
713 if (rc != 0)
714 goto import_cat_failure;
715 }
716
717 return 0;
718
719import_cat_failure:
720 ebitmap_destroy(&context->range.level[0].cat);
721 ebitmap_destroy(&context->range.level[1].cat);
722 return rc;
723}
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 90c5e88987fa..df6032c6d492 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -10,6 +10,13 @@
10 * 10 *
11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12 */ 12 */
13/*
14 * Updated: Hewlett-Packard <paul.moore@hp.com>
15 *
16 * Added support to import/export the MLS label
17 *
18 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
19 */
13 20
14#ifndef _SS_MLS_H_ 21#ifndef _SS_MLS_H_
15#define _SS_MLS_H_ 22#define _SS_MLS_H_
@@ -62,5 +69,19 @@ int mls_compute_sid(struct context *scontext,
62int mls_setup_user_range(struct context *fromcon, struct user_datum *user, 69int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
63 struct context *usercon); 70 struct context *usercon);
64 71
72void mls_export_lvl(const struct context *context, u32 *low, u32 *high);
73void mls_import_lvl(struct context *context, u32 low, u32 high);
74
75int mls_export_cat(const struct context *context,
76 unsigned char **low,
77 size_t *low_len,
78 unsigned char **high,
79 size_t *high_len);
80int mls_import_cat(struct context *context,
81 const unsigned char *low,
82 size_t low_len,
83 const unsigned char *high,
84 size_t high_len);
85
65#endif /* _SS_MLS_H */ 86#endif /* _SS_MLS_H */
66 87
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 */