aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/selinux/include/security.h24
-rw-r--r--security/selinux/include/selinux_netlabel.h71
-rw-r--r--security/selinux/netlabel.c363
-rw-r--r--security/selinux/ss/services.c423
5 files changed, 481 insertions, 402 deletions
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index faf2e02e4410..dc3502e30b19 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -8,5 +8,7 @@ selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o exports.o
8 8
9selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o 9selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
10 10
11selinux-$(CONFIG_NETLABEL) += netlabel.o
12
11EXTRA_CFLAGS += -Isecurity/selinux/include 13EXTRA_CFLAGS += -Isecurity/selinux/include
12 14
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 210eec77e7ff..605b07165af8 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -35,6 +35,7 @@
35#endif 35#endif
36 36
37struct sk_buff; 37struct sk_buff;
38struct netlbl_lsm_secattr;
38 39
39extern int selinux_enabled; 40extern int selinux_enabled;
40extern int selinux_mls_enabled; 41extern int selinux_mls_enabled;
@@ -102,5 +103,28 @@ int security_fs_use(const char *fstype, unsigned int *behavior,
102int security_genfs_sid(const char *fstype, char *name, u16 sclass, 103int security_genfs_sid(const char *fstype, char *name, u16 sclass,
103 u32 *sid); 104 u32 *sid);
104 105
106#ifdef CONFIG_NETLABEL
107int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
108 u32 base_sid,
109 u32 *sid);
110
111int security_netlbl_sid_to_secattr(u32 sid,
112 struct netlbl_lsm_secattr *secattr);
113#else
114static inline int security_netlbl_secattr_to_sid(
115 struct netlbl_lsm_secattr *secattr,
116 u32 base_sid,
117 u32 *sid)
118{
119 return -EIDRM;
120}
121
122static inline int security_netlbl_sid_to_secattr(u32 sid,
123 struct netlbl_lsm_secattr *secattr)
124{
125 return -ENOENT;
126}
127#endif /* CONFIG_NETLABEL */
128
105#endif /* _SELINUX_SECURITY_H_ */ 129#endif /* _SELINUX_SECURITY_H_ */
106 130
diff --git a/security/selinux/include/selinux_netlabel.h b/security/selinux/include/selinux_netlabel.h
index 2a732c9033e3..218e3f77c350 100644
--- a/security/selinux/include/selinux_netlabel.h
+++ b/security/selinux/include/selinux_netlabel.h
@@ -38,19 +38,22 @@
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_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid); 41
42int selinux_netlbl_socket_post_create(struct socket *sock);
43void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
44int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
45 struct sk_buff *skb,
46 struct avc_audit_data *ad);
47void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 42void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
48 int family); 43 int family);
49void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, 44void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
50 int family); 45 int family);
51void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, 46void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
52 struct sk_security_struct *newssec); 47 struct sk_security_struct *newssec);
48
49int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid);
50
51void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
52int selinux_netlbl_socket_post_create(struct socket *sock);
53int selinux_netlbl_inode_permission(struct inode *inode, int mask); 53int selinux_netlbl_inode_permission(struct inode *inode, int mask);
54int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
55 struct sk_buff *skb,
56 struct avc_audit_data *ad);
54int selinux_netlbl_socket_setsockopt(struct socket *sock, 57int selinux_netlbl_socket_setsockopt(struct socket *sock,
55 int level, 58 int level,
56 int optname); 59 int optname);
@@ -60,59 +63,53 @@ static inline void selinux_netlbl_cache_invalidate(void)
60 return; 63 return;
61} 64}
62 65
63static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 66static inline void selinux_netlbl_sk_security_reset(
64 u32 base_sid, 67 struct sk_security_struct *ssec,
65 u32 *sid) 68 int family)
66{ 69{
67 *sid = SECSID_NULL; 70 return;
68 return 0;
69} 71}
70 72static inline void selinux_netlbl_sk_security_init(
71static inline int selinux_netlbl_socket_post_create(struct socket *sock) 73 struct sk_security_struct *ssec,
74 int family)
72{ 75{
73 return 0; 76 return;
74} 77}
75 78static inline void selinux_netlbl_sk_security_clone(
76static inline void selinux_netlbl_sock_graft(struct sock *sk, 79 struct sk_security_struct *ssec,
77 struct socket *sock) 80 struct sk_security_struct *newssec)
78{ 81{
79 return; 82 return;
80} 83}
81 84
82static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 85static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
83 struct sk_buff *skb, 86 u32 base_sid,
84 struct avc_audit_data *ad) 87 u32 *sid)
85{ 88{
89 *sid = SECSID_NULL;
86 return 0; 90 return 0;
87} 91}
88 92
89static inline void selinux_netlbl_sk_security_reset( 93static inline void selinux_netlbl_sock_graft(struct sock *sk,
90 struct sk_security_struct *ssec, 94 struct socket *sock)
91 int family)
92{
93 return;
94}
95
96static inline void selinux_netlbl_sk_security_init(
97 struct sk_security_struct *ssec,
98 int family)
99{ 95{
100 return; 96 return;
101} 97}
102 98static inline int selinux_netlbl_socket_post_create(struct socket *sock)
103static inline void selinux_netlbl_sk_security_clone(
104 struct sk_security_struct *ssec,
105 struct sk_security_struct *newssec)
106{ 99{
107 return; 100 return 0;
108} 101}
109
110static inline int selinux_netlbl_inode_permission(struct inode *inode, 102static inline int selinux_netlbl_inode_permission(struct inode *inode,
111 int mask) 103 int mask)
112{ 104{
113 return 0; 105 return 0;
114} 106}
115 107static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
108 struct sk_buff *skb,
109 struct avc_audit_data *ad)
110{
111 return 0;
112}
116static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, 113static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
117 int level, 114 int level,
118 int optname) 115 int optname)
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
new file mode 100644
index 000000000000..bf8750791dd1
--- /dev/null
+++ b/security/selinux/netlabel.c
@@ -0,0 +1,363 @@
1/*
2 * SELinux NetLabel Support
3 *
4 * This file provides the necessary glue to tie NetLabel into the SELinux
5 * subsystem.
6 *
7 * Author: Paul Moore <paul.moore@hp.com>
8 *
9 */
10
11/*
12 * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
22 * the GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <linux/spinlock.h>
31#include <linux/rcupdate.h>
32#include <net/sock.h>
33#include <net/netlabel.h>
34
35#include "objsec.h"
36#include "security.h"
37
38/**
39 * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
40 * @sock: the socket to label
41 * @sid: the SID to use
42 *
43 * Description:
44 * Attempt to label a socket using the NetLabel mechanism using the given
45 * SID. Returns zero values on success, negative values on failure. The
46 * caller is responsibile for calling rcu_read_lock() before calling this
47 * this function and rcu_read_unlock() after this function returns.
48 *
49 */
50static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
51{
52 int rc;
53 struct sk_security_struct *sksec = sock->sk->sk_security;
54 struct netlbl_lsm_secattr secattr;
55
56 rc = security_netlbl_sid_to_secattr(sid, &secattr);
57 if (rc != 0)
58 return rc;
59
60 rc = netlbl_socket_setattr(sock, &secattr);
61 if (rc == 0) {
62 spin_lock_bh(&sksec->nlbl_lock);
63 sksec->nlbl_state = NLBL_LABELED;
64 spin_unlock_bh(&sksec->nlbl_lock);
65 }
66
67 return rc;
68}
69
70/**
71 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
72 *
73 * Description:
74 * Invalidate the NetLabel security attribute mapping cache.
75 *
76 */
77void selinux_netlbl_cache_invalidate(void)
78{
79 netlbl_cache_invalidate();
80}
81
82/**
83 * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
84 * @ssec: the sk_security_struct
85 * @family: the socket family
86 *
87 * Description:
88 * Called when the NetLabel state of a sk_security_struct needs to be reset.
89 * The caller is responsibile for all the NetLabel sk_security_struct locking.
90 *
91 */
92void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
93 int family)
94{
95 if (family == PF_INET)
96 ssec->nlbl_state = NLBL_REQUIRE;
97 else
98 ssec->nlbl_state = NLBL_UNSET;
99}
100
101/**
102 * selinux_netlbl_sk_security_init - Setup the NetLabel fields
103 * @ssec: the sk_security_struct
104 * @family: the socket family
105 *
106 * Description:
107 * Called when a new sk_security_struct is allocated to initialize the NetLabel
108 * fields.
109 *
110 */
111void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
112 int family)
113{
114 /* No locking needed, we are the only one who has access to ssec */
115 selinux_netlbl_sk_security_reset(ssec, family);
116 spin_lock_init(&ssec->nlbl_lock);
117}
118
119/**
120 * selinux_netlbl_sk_security_clone - Copy the NetLabel fields
121 * @ssec: the original sk_security_struct
122 * @newssec: the cloned sk_security_struct
123 *
124 * Description:
125 * Clone the NetLabel specific sk_security_struct fields from @ssec to
126 * @newssec.
127 *
128 */
129void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
130 struct sk_security_struct *newssec)
131{
132 /* We don't need to take newssec->nlbl_lock because we are the only
133 * thread with access to newssec, but we do need to take the RCU read
134 * lock as other threads could have access to ssec */
135 rcu_read_lock();
136 selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
137 newssec->sclass = ssec->sclass;
138 rcu_read_unlock();
139}
140
141/**
142 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
143 * @skb: the packet
144 * @base_sid: the SELinux SID to use as a context for MLS only attributes
145 * @sid: the SID
146 *
147 * Description:
148 * Call the NetLabel mechanism to get the security attributes of the given
149 * packet and use those attributes to determine the correct context/SID to
150 * assign to the packet. Returns zero on success, negative values on failure.
151 *
152 */
153int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
154{
155 int rc;
156 struct netlbl_lsm_secattr secattr;
157
158 netlbl_secattr_init(&secattr);
159 rc = netlbl_skbuff_getattr(skb, &secattr);
160 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
161 rc = security_netlbl_secattr_to_sid(&secattr,
162 base_sid,
163 sid);
164 else
165 *sid = SECSID_NULL;
166 netlbl_secattr_destroy(&secattr);
167
168 return rc;
169}
170
171/**
172 * selinux_netlbl_sock_graft - Netlabel the new socket
173 * @sk: the new connection
174 * @sock: the new socket
175 *
176 * Description:
177 * The connection represented by @sk is being grafted onto @sock so set the
178 * socket's NetLabel to match the SID of @sk.
179 *
180 */
181void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
182{
183 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
184 struct sk_security_struct *sksec = sk->sk_security;
185 struct netlbl_lsm_secattr secattr;
186 u32 nlbl_peer_sid;
187
188 sksec->sclass = isec->sclass;
189
190 rcu_read_lock();
191
192 if (sksec->nlbl_state != NLBL_REQUIRE) {
193 rcu_read_unlock();
194 return;
195 }
196
197 netlbl_secattr_init(&secattr);
198 if (netlbl_sock_getattr(sk, &secattr) == 0 &&
199 secattr.flags != NETLBL_SECATTR_NONE &&
200 security_netlbl_secattr_to_sid(&secattr,
201 SECINITSID_UNLABELED,
202 &nlbl_peer_sid) == 0)
203 sksec->peer_sid = nlbl_peer_sid;
204 netlbl_secattr_destroy(&secattr);
205
206 /* Try to set the NetLabel on the socket to save time later, if we fail
207 * here we will pick up the pieces in later calls to
208 * selinux_netlbl_inode_permission(). */
209 selinux_netlbl_socket_setsid(sock, sksec->sid);
210
211 rcu_read_unlock();
212}
213
214/**
215 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
216 * @sock: the socket to label
217 *
218 * Description:
219 * Attempt to label a socket using the NetLabel mechanism using the given
220 * SID. Returns zero values on success, negative values on failure.
221 *
222 */
223int selinux_netlbl_socket_post_create(struct socket *sock)
224{
225 int rc = 0;
226 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
227 struct sk_security_struct *sksec = sock->sk->sk_security;
228
229 sksec->sclass = isec->sclass;
230
231 rcu_read_lock();
232 if (sksec->nlbl_state == NLBL_REQUIRE)
233 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
234 rcu_read_unlock();
235
236 return rc;
237}
238
239/**
240 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
241 * @inode: the file descriptor's inode
242 * @mask: the permission mask
243 *
244 * Description:
245 * Looks at a file's inode and if it is marked as a socket protected by
246 * NetLabel then verify that the socket has been labeled, if not try to label
247 * the socket now with the inode's SID. Returns zero on success, negative
248 * values on failure.
249 *
250 */
251int selinux_netlbl_inode_permission(struct inode *inode, int mask)
252{
253 int rc;
254 struct sk_security_struct *sksec;
255 struct socket *sock;
256
257 if (!S_ISSOCK(inode->i_mode) ||
258 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
259 return 0;
260 sock = SOCKET_I(inode);
261 sksec = sock->sk->sk_security;
262
263 rcu_read_lock();
264 if (sksec->nlbl_state != NLBL_REQUIRE) {
265 rcu_read_unlock();
266 return 0;
267 }
268 local_bh_disable();
269 bh_lock_sock_nested(sock->sk);
270 rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
271 bh_unlock_sock(sock->sk);
272 local_bh_enable();
273 rcu_read_unlock();
274
275 return rc;
276}
277
278/**
279 * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
280 * @sksec: the sock's sk_security_struct
281 * @skb: the packet
282 * @ad: the audit data
283 *
284 * Description:
285 * Fetch the NetLabel security attributes from @skb and perform an access check
286 * against the receiving socket. Returns zero on success, negative values on
287 * error.
288 *
289 */
290int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
291 struct sk_buff *skb,
292 struct avc_audit_data *ad)
293{
294 int rc;
295 u32 netlbl_sid;
296 u32 recv_perm;
297
298 rc = selinux_netlbl_skbuff_getsid(skb,
299 SECINITSID_UNLABELED,
300 &netlbl_sid);
301 if (rc != 0)
302 return rc;
303
304 if (netlbl_sid == SECSID_NULL)
305 return 0;
306
307 switch (sksec->sclass) {
308 case SECCLASS_UDP_SOCKET:
309 recv_perm = UDP_SOCKET__RECVFROM;
310 break;
311 case SECCLASS_TCP_SOCKET:
312 recv_perm = TCP_SOCKET__RECVFROM;
313 break;
314 default:
315 recv_perm = RAWIP_SOCKET__RECVFROM;
316 }
317
318 rc = avc_has_perm(sksec->sid,
319 netlbl_sid,
320 sksec->sclass,
321 recv_perm,
322 ad);
323 if (rc == 0)
324 return 0;
325
326 netlbl_skbuff_err(skb, rc);
327 return rc;
328}
329
330/**
331 * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
332 * @sock: the socket
333 * @level: the socket level or protocol
334 * @optname: the socket option name
335 *
336 * Description:
337 * Check the setsockopt() call and if the user is trying to replace the IP
338 * options on a socket and a NetLabel is in place for the socket deny the
339 * access; otherwise allow the access. Returns zero when the access is
340 * allowed, -EACCES when denied, and other negative values on error.
341 *
342 */
343int selinux_netlbl_socket_setsockopt(struct socket *sock,
344 int level,
345 int optname)
346{
347 int rc = 0;
348 struct sk_security_struct *sksec = sock->sk->sk_security;
349 struct netlbl_lsm_secattr secattr;
350
351 rcu_read_lock();
352 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
353 sksec->nlbl_state == NLBL_LABELED) {
354 netlbl_secattr_init(&secattr);
355 rc = netlbl_socket_getattr(sock, &secattr);
356 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
357 rc = -EACCES;
358 netlbl_secattr_destroy(&secattr);
359 }
360 rcu_read_unlock();
361
362 return rc;
363}
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 */