aboutsummaryrefslogtreecommitdiffstats
path: root/security
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
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')
-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 */