aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2009-03-27 17:10:34 -0400
committerJames Morris <jmorris@namei.org>2009-03-28 00:01:36 -0400
commit389fb800ac8be2832efedd19978a2b8ced37eb61 (patch)
treefa0bc16050dfb491aa05f76b54fa4c167de96376 /security
parent284904aa79466a4736f4c775fdbe5c7407fa136c (diff)
netlabel: Label incoming TCP connections correctly in SELinux
The current NetLabel/SELinux behavior for incoming TCP connections works but only through a series of happy coincidences that rely on the limited nature of standard CIPSO (only able to convey MLS attributes) and the write equality imposed by the SELinux MLS constraints. The problem is that network sockets created as the result of an incoming TCP connection were not on-the-wire labeled based on the security attributes of the parent socket but rather based on the wire label of the remote peer. The issue had to do with how IP options were managed as part of the network stack and where the LSM hooks were in relation to the code which set the IP options on these newly created child sockets. While NetLabel/SELinux did correctly set the socket's on-the-wire label it was promptly cleared by the network stack and reset based on the IP options of the remote peer. This patch, in conjunction with a prior patch that adjusted the LSM hook locations, works to set the correct on-the-wire label format for new incoming connections through the security_inet_conn_request() hook. Besides the correct behavior there are many advantages to this change, the most significant is that all of the NetLabel socket labeling code in SELinux now lives in hooks which can return error codes to the core stack which allows us to finally get ride of the selinux_netlbl_inode_permission() logic which greatly simplfies the NetLabel/SELinux glue code. In the process of developing this patch I also ran into a small handful of AF_INET6 cleanliness issues that have been fixed which should make the code safer and easier to extend in the future. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/hooks.c54
-rw-r--r--security/selinux/include/netlabel.h27
-rw-r--r--security/selinux/netlabel.c186
-rw-r--r--security/smack/smack_lsm.c2
4 files changed, 82 insertions, 187 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7c52ba243c6..ee2e781d11d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -311,7 +311,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
311 ssec->sid = SECINITSID_UNLABELED; 311 ssec->sid = SECINITSID_UNLABELED;
312 sk->sk_security = ssec; 312 sk->sk_security = ssec;
313 313
314 selinux_netlbl_sk_security_reset(ssec, family); 314 selinux_netlbl_sk_security_reset(ssec);
315 315
316 return 0; 316 return 0;
317} 317}
@@ -2945,7 +2945,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2945static int selinux_revalidate_file_permission(struct file *file, int mask) 2945static int selinux_revalidate_file_permission(struct file *file, int mask)
2946{ 2946{
2947 const struct cred *cred = current_cred(); 2947 const struct cred *cred = current_cred();
2948 int rc;
2949 struct inode *inode = file->f_path.dentry->d_inode; 2948 struct inode *inode = file->f_path.dentry->d_inode;
2950 2949
2951 if (!mask) { 2950 if (!mask) {
@@ -2957,29 +2956,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
2957 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 2956 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2958 mask |= MAY_APPEND; 2957 mask |= MAY_APPEND;
2959 2958
2960 rc = file_has_perm(cred, file, 2959 return file_has_perm(cred, file,
2961 file_mask_to_av(inode->i_mode, mask)); 2960 file_mask_to_av(inode->i_mode, mask));
2962 if (rc)
2963 return rc;
2964
2965 return selinux_netlbl_inode_permission(inode, mask);
2966} 2961}
2967 2962
2968static int selinux_file_permission(struct file *file, int mask) 2963static int selinux_file_permission(struct file *file, int mask)
2969{ 2964{
2970 struct inode *inode = file->f_path.dentry->d_inode; 2965 if (!mask)
2971 struct file_security_struct *fsec = file->f_security;
2972 struct inode_security_struct *isec = inode->i_security;
2973 u32 sid = current_sid();
2974
2975 if (!mask) {
2976 /* No permission to check. Existence test. */ 2966 /* No permission to check. Existence test. */
2977 return 0; 2967 return 0;
2978 }
2979
2980 if (sid == fsec->sid && fsec->isid == isec->sid
2981 && fsec->pseqno == avc_policy_seqno())
2982 return selinux_netlbl_inode_permission(inode, mask);
2983 2968
2984 return selinux_revalidate_file_permission(file, mask); 2969 return selinux_revalidate_file_permission(file, mask);
2985} 2970}
@@ -3723,7 +3708,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
3723 sksec = sock->sk->sk_security; 3708 sksec = sock->sk->sk_security;
3724 sksec->sid = isec->sid; 3709 sksec->sid = isec->sid;
3725 sksec->sclass = isec->sclass; 3710 sksec->sclass = isec->sclass;
3726 err = selinux_netlbl_socket_post_create(sock); 3711 err = selinux_netlbl_socket_post_create(sock->sk, family);
3727 } 3712 }
3728 3713
3729 return err; 3714 return err;
@@ -3914,13 +3899,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3914static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 3899static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
3915 int size) 3900 int size)
3916{ 3901{
3917 int rc; 3902 return socket_has_perm(current, sock, SOCKET__WRITE);
3918
3919 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3920 if (rc)
3921 return rc;
3922
3923 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
3924} 3903}
3925 3904
3926static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, 3905static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -4304,7 +4283,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4304 newssec->peer_sid = ssec->peer_sid; 4283 newssec->peer_sid = ssec->peer_sid;
4305 newssec->sclass = ssec->sclass; 4284 newssec->sclass = ssec->sclass;
4306 4285
4307 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); 4286 selinux_netlbl_sk_security_reset(newssec);
4308} 4287}
4309 4288
4310static void selinux_sk_getsecid(struct sock *sk, u32 *secid) 4289static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4348,16 +4327,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4348 if (peersid == SECSID_NULL) { 4327 if (peersid == SECSID_NULL) {
4349 req->secid = sksec->sid; 4328 req->secid = sksec->sid;
4350 req->peer_secid = SECSID_NULL; 4329 req->peer_secid = SECSID_NULL;
4351 return 0; 4330 } else {
4331 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4332 if (err)
4333 return err;
4334 req->secid = newsid;
4335 req->peer_secid = peersid;
4352 } 4336 }
4353 4337
4354 err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 4338 return selinux_netlbl_inet_conn_request(req, family);
4355 if (err)
4356 return err;
4357
4358 req->secid = newsid;
4359 req->peer_secid = peersid;
4360 return 0;
4361} 4339}
4362 4340
4363static void selinux_inet_csk_clone(struct sock *newsk, 4341static void selinux_inet_csk_clone(struct sock *newsk,
@@ -4374,7 +4352,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
4374 4352
4375 /* We don't need to take any sort of lock here as we are the only 4353 /* We don't need to take any sort of lock here as we are the only
4376 * thread with access to newsksec */ 4354 * thread with access to newsksec */
4377 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); 4355 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
4378} 4356}
4379 4357
4380static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) 4358static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
@@ -4387,8 +4365,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
4387 family = PF_INET; 4365 family = PF_INET;
4388 4366
4389 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 4367 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
4390
4391 selinux_netlbl_inet_conn_established(sk, family);
4392} 4368}
4393 4369
4394static void selinux_req_classify_flow(const struct request_sock *req, 4370static void selinux_req_classify_flow(const struct request_sock *req,
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index b913c8d0603..b4b5b9b2f0b 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -32,6 +32,7 @@
32#include <linux/net.h> 32#include <linux/net.h>
33#include <linux/skbuff.h> 33#include <linux/skbuff.h>
34#include <net/sock.h> 34#include <net/sock.h>
35#include <net/request_sock.h>
35 36
36#include "avc.h" 37#include "avc.h"
37#include "objsec.h" 38#include "objsec.h"
@@ -42,8 +43,7 @@ void selinux_netlbl_cache_invalidate(void);
42void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); 43void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
43 44
44void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); 45void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
45void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 46void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec);
46 int family);
47 47
48int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 48int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
49 u16 family, 49 u16 family,
@@ -53,9 +53,9 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
53 u16 family, 53 u16 family,
54 u32 sid); 54 u32 sid);
55 55
56void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); 56int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
57int selinux_netlbl_socket_post_create(struct socket *sock); 57void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
58int selinux_netlbl_inode_permission(struct inode *inode, int mask); 58int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
59int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 59int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
60 struct sk_buff *skb, 60 struct sk_buff *skb,
61 u16 family, 61 u16 family,
@@ -85,8 +85,7 @@ static inline void selinux_netlbl_sk_security_free(
85} 85}
86 86
87static inline void selinux_netlbl_sk_security_reset( 87static inline void selinux_netlbl_sk_security_reset(
88 struct sk_security_struct *ssec, 88 struct sk_security_struct *ssec)
89 int family)
90{ 89{
91 return; 90 return;
92} 91}
@@ -113,17 +112,17 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk,
113 return 0; 112 return 0;
114} 113}
115 114
116static inline void selinux_netlbl_inet_conn_established(struct sock *sk, 115static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
117 u16 family) 116 u16 family)
118{ 117{
119 return; 118 return 0;
120} 119}
121static inline int selinux_netlbl_socket_post_create(struct socket *sock) 120static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
122{ 121{
123 return 0; 122 return;
124} 123}
125static inline int selinux_netlbl_inode_permission(struct inode *inode, 124static inline int selinux_netlbl_socket_post_create(struct sock *sk,
126 int mask) 125 u16 family)
127{ 126{
128 return 0; 127 return 0;
129} 128}
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 350794ab9b4..2e984413c7b 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -100,41 +100,6 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
100} 100}
101 101
102/** 102/**
103 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
104 * @sk: the socket to label
105 *
106 * Description:
107 * Attempt to label a socket using the NetLabel mechanism. Returns zero values
108 * on success, negative values on failure.
109 *
110 */
111static int selinux_netlbl_sock_setsid(struct sock *sk)
112{
113 int rc;
114 struct sk_security_struct *sksec = sk->sk_security;
115 struct netlbl_lsm_secattr *secattr;
116
117 if (sksec->nlbl_state != NLBL_REQUIRE)
118 return 0;
119
120 secattr = selinux_netlbl_sock_genattr(sk);
121 if (secattr == NULL)
122 return -ENOMEM;
123 rc = netlbl_sock_setattr(sk, secattr);
124 switch (rc) {
125 case 0:
126 sksec->nlbl_state = NLBL_LABELED;
127 break;
128 case -EDESTADDRREQ:
129 sksec->nlbl_state = NLBL_REQSKB;
130 rc = 0;
131 break;
132 }
133
134 return rc;
135}
136
137/**
138 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 103 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
139 * 104 *
140 * Description: 105 * Description:
@@ -188,13 +153,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
188 * The caller is responsibile for all the NetLabel sk_security_struct locking. 153 * The caller is responsibile for all the NetLabel sk_security_struct locking.
189 * 154 *
190 */ 155 */
191void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 156void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
192 int family)
193{ 157{
194 if (family == PF_INET) 158 ssec->nlbl_state = NLBL_UNSET;
195 ssec->nlbl_state = NLBL_REQUIRE;
196 else
197 ssec->nlbl_state = NLBL_UNSET;
198} 159}
199 160
200/** 161/**
@@ -281,127 +242,86 @@ skbuff_setsid_return:
281} 242}
282 243
283/** 244/**
284 * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection 245 * selinux_netlbl_inet_conn_request - Label an incoming stream connection
285 * @sk: the new connection 246 * @req: incoming connection request socket
286 * 247 *
287 * Description: 248 * Description:
288 * A new connection has been established on @sk so make sure it is labeled 249 * A new incoming connection request is represented by @req, we need to label
289 * correctly with the NetLabel susbsystem. 250 * the new request_sock here and the stack will ensure the on-the-wire label
251 * will get preserved when a full sock is created once the connection handshake
252 * is complete. Returns zero on success, negative values on failure.
290 * 253 *
291 */ 254 */
292void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) 255int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
293{ 256{
294 int rc; 257 int rc;
295 struct sk_security_struct *sksec = sk->sk_security; 258 struct netlbl_lsm_secattr secattr;
296 struct netlbl_lsm_secattr *secattr;
297 struct inet_sock *sk_inet = inet_sk(sk);
298 struct sockaddr_in addr;
299
300 if (sksec->nlbl_state != NLBL_REQUIRE)
301 return;
302 259
303 secattr = selinux_netlbl_sock_genattr(sk); 260 if (family != PF_INET)
304 if (secattr == NULL) 261 return 0;
305 return;
306 262
307 rc = netlbl_sock_setattr(sk, secattr); 263 netlbl_secattr_init(&secattr);
308 switch (rc) { 264 rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
309 case 0: 265 if (rc != 0)
310 sksec->nlbl_state = NLBL_LABELED; 266 goto inet_conn_request_return;
311 break; 267 rc = netlbl_req_setattr(req, &secattr);
312 case -EDESTADDRREQ: 268inet_conn_request_return:
313 /* no PF_INET6 support yet because we don't support any IPv6 269 netlbl_secattr_destroy(&secattr);
314 * labeling protocols */ 270 return rc;
315 if (family != PF_INET) {
316 sksec->nlbl_state = NLBL_UNSET;
317 return;
318 }
319
320 addr.sin_family = family;
321 addr.sin_addr.s_addr = sk_inet->daddr;
322 if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
323 secattr) != 0) {
324 /* we failed to label the connected socket (could be
325 * for a variety of reasons, the actual "why" isn't
326 * important here) so we have to go to our backup plan,
327 * labeling the packets individually in the netfilter
328 * local output hook. this is okay but we need to
329 * adjust the MSS of the connection to take into
330 * account any labeling overhead, since we don't know
331 * the exact overhead at this point we'll use the worst
332 * case value which is 40 bytes for IPv4 */
333 struct inet_connection_sock *sk_conn = inet_csk(sk);
334 sk_conn->icsk_ext_hdr_len += 40 -
335 (sk_inet->opt ? sk_inet->opt->optlen : 0);
336 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
337
338 sksec->nlbl_state = NLBL_REQSKB;
339 } else
340 sksec->nlbl_state = NLBL_CONNLABELED;
341 break;
342 default:
343 /* note that we are failing to label the socket which could be
344 * a bad thing since it means traffic could leave the system
345 * without the desired labeling, however, all is not lost as
346 * we have a check in selinux_netlbl_inode_permission() to
347 * pick up the pieces that we might drop here because we can't
348 * return an error code */
349 break;
350 }
351} 271}
352 272
353/** 273/**
354 * selinux_netlbl_socket_post_create - Label a socket using NetLabel 274 * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
355 * @sock: the socket to label 275 * @sk: the new sock
356 * 276 *
357 * Description: 277 * Description:
358 * Attempt to label a socket using the NetLabel mechanism using the given 278 * A new connection has been established using @sk, we've already labeled the
359 * SID. Returns zero values on success, negative values on failure. 279 * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
280 * we need to set the NetLabel state here since we now have a sock structure.
360 * 281 *
361 */ 282 */
362int selinux_netlbl_socket_post_create(struct socket *sock) 283void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
363{ 284{
364 return selinux_netlbl_sock_setsid(sock->sk); 285 struct sk_security_struct *sksec = sk->sk_security;
286
287 if (family == PF_INET)
288 sksec->nlbl_state = NLBL_LABELED;
289 else
290 sksec->nlbl_state = NLBL_UNSET;
365} 291}
366 292
367/** 293/**
368 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled 294 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
369 * @inode: the file descriptor's inode 295 * @sock: the socket to label
370 * @mask: the permission mask 296 * @family: protocol family
371 * 297 *
372 * Description: 298 * Description:
373 * Looks at a file's inode and if it is marked as a socket protected by 299 * Attempt to label a socket using the NetLabel mechanism using the given
374 * NetLabel then verify that the socket has been labeled, if not try to label 300 * SID. Returns zero values on success, negative values on failure.
375 * the socket now with the inode's SID. Returns zero on success, negative
376 * values on failure.
377 * 301 *
378 */ 302 */
379int selinux_netlbl_inode_permission(struct inode *inode, int mask) 303int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
380{ 304{
381 int rc; 305 int rc;
382 struct sock *sk; 306 struct sk_security_struct *sksec = sk->sk_security;
383 struct socket *sock; 307 struct netlbl_lsm_secattr *secattr;
384 struct sk_security_struct *sksec;
385 308
386 if (!S_ISSOCK(inode->i_mode) || 309 if (family != PF_INET)
387 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
388 return 0;
389 sock = SOCKET_I(inode);
390 sk = sock->sk;
391 if (sk == NULL)
392 return 0;
393 sksec = sk->sk_security;
394 if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE)
395 return 0; 310 return 0;
396 311
397 local_bh_disable(); 312 secattr = selinux_netlbl_sock_genattr(sk);
398 bh_lock_sock_nested(sk); 313 if (secattr == NULL)
399 if (likely(sksec->nlbl_state == NLBL_REQUIRE)) 314 return -ENOMEM;
400 rc = selinux_netlbl_sock_setsid(sk); 315 rc = netlbl_sock_setattr(sk, family, secattr);
401 else 316 switch (rc) {
317 case 0:
318 sksec->nlbl_state = NLBL_LABELED;
319 break;
320 case -EDESTADDRREQ:
321 sksec->nlbl_state = NLBL_REQSKB;
402 rc = 0; 322 rc = 0;
403 bh_unlock_sock(sk); 323 break;
404 local_bh_enable(); 324 }
405 325
406 return rc; 326 return rc;
407} 327}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fd20d15f5b9..23ad420a49a 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1387,7 +1387,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
1387 else { 1387 else {
1388 netlbl_secattr_init(&secattr); 1388 netlbl_secattr_init(&secattr);
1389 smack_to_secattr(ssp->smk_out, &secattr); 1389 smack_to_secattr(ssp->smk_out, &secattr);
1390 rc = netlbl_sock_setattr(sk, &secattr); 1390 rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr);
1391 netlbl_secattr_destroy(&secattr); 1391 netlbl_secattr_destroy(&secattr);
1392 } 1392 }
1393 1393