aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVenkat Yekkirala <vyekkirala@trustedcs.com>2006-11-08 18:04:09 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:21:33 -0500
commit6b877699c6f1efede4545bcecc367786a472eedb (patch)
treec0a60dc90578fa9f16d4496e2700bc285eab47c0
parentc1a856c9640c9ff3d70bbd8214b6a0974609eef8 (diff)
SELinux: Return correct context for SO_PEERSEC
Fix SO_PEERSEC for tcp sockets to return the security context of the peer (as represented by the SA from the peer) as opposed to the SA used by the local/source socket. Signed-off-by: Venkat Yekkirala <vyekkirala@TrustedCS.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--include/linux/security.h16
-rw-r--r--include/net/request_sock.h1
-rw-r--r--net/ipv4/tcp_input.c2
-rw-r--r--security/dummy.c6
-rw-r--r--security/selinux/hooks.c21
-rw-r--r--security/selinux/include/xfrm.h12
-rw-r--r--security/selinux/xfrm.c40
7 files changed, 50 insertions, 48 deletions
diff --git a/include/linux/security.h b/include/linux/security.h
index a509329a669b..84cebcdb3f83 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -826,6 +826,8 @@ struct request_sock;
826 * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid. 826 * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid.
827 * @inet_csk_clone: 827 * @inet_csk_clone:
828 * Sets the new child socket's sid to the openreq sid. 828 * Sets the new child socket's sid to the openreq sid.
829 * @inet_conn_established:
830 * Sets the connection's peersid to the secmark on skb.
829 * @req_classify_flow: 831 * @req_classify_flow:
830 * Sets the flow's sid to the openreq sid. 832 * Sets the flow's sid to the openreq sid.
831 * 833 *
@@ -1368,6 +1370,7 @@ struct security_operations {
1368 int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb, 1370 int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb,
1369 struct request_sock *req); 1371 struct request_sock *req);
1370 void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req); 1372 void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req);
1373 void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb);
1371 void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl); 1374 void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl);
1372#endif /* CONFIG_SECURITY_NETWORK */ 1375#endif /* CONFIG_SECURITY_NETWORK */
1373 1376
@@ -2961,9 +2964,15 @@ static inline void security_inet_csk_clone(struct sock *newsk,
2961{ 2964{
2962 security_ops->inet_csk_clone(newsk, req); 2965 security_ops->inet_csk_clone(newsk, req);
2963} 2966}
2967
2968static inline void security_inet_conn_established(struct sock *sk,
2969 struct sk_buff *skb)
2970{
2971 security_ops->inet_conn_established(sk, skb);
2972}
2964#else /* CONFIG_SECURITY_NETWORK */ 2973#else /* CONFIG_SECURITY_NETWORK */
2965static inline int security_unix_stream_connect(struct socket * sock, 2974static inline int security_unix_stream_connect(struct socket * sock,
2966 struct socket * other, 2975 struct socket * other,
2967 struct sock * newsk) 2976 struct sock * newsk)
2968{ 2977{
2969 return 0; 2978 return 0;
@@ -3110,6 +3119,11 @@ static inline void security_inet_csk_clone(struct sock *newsk,
3110 const struct request_sock *req) 3119 const struct request_sock *req)
3111{ 3120{
3112} 3121}
3122
3123static inline void security_inet_conn_established(struct sock *sk,
3124 struct sk_buff *skb)
3125{
3126}
3113#endif /* CONFIG_SECURITY_NETWORK */ 3127#endif /* CONFIG_SECURITY_NETWORK */
3114 3128
3115#ifdef CONFIG_SECURITY_NETWORK_XFRM 3129#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index 8e165ca16bd8..f743a941a4f2 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -54,6 +54,7 @@ struct request_sock {
54 struct request_sock_ops *rsk_ops; 54 struct request_sock_ops *rsk_ops;
55 struct sock *sk; 55 struct sock *sk;
56 u32 secid; 56 u32 secid;
57 u32 peer_secid;
57}; 58};
58 59
59static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) 60static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index cf06accbe687..4a8c96cdec7d 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4230,6 +4230,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
4230 mb(); 4230 mb();
4231 tcp_set_state(sk, TCP_ESTABLISHED); 4231 tcp_set_state(sk, TCP_ESTABLISHED);
4232 4232
4233 security_inet_conn_established(sk, skb);
4234
4233 /* Make sure socket is routed, for correct metrics. */ 4235 /* Make sure socket is routed, for correct metrics. */
4234 icsk->icsk_af_ops->rebuild_header(sk); 4236 icsk->icsk_af_ops->rebuild_header(sk);
4235 4237
diff --git a/security/dummy.c b/security/dummy.c
index 838d8442cf3c..0148d1518dd1 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -828,6 +828,11 @@ static inline void dummy_inet_csk_clone(struct sock *newsk,
828{ 828{
829} 829}
830 830
831static inline void dummy_inet_conn_established(struct sock *sk,
832 struct sk_buff *skb)
833{
834}
835
831static inline void dummy_req_classify_flow(const struct request_sock *req, 836static inline void dummy_req_classify_flow(const struct request_sock *req,
832 struct flowi *fl) 837 struct flowi *fl)
833{ 838{
@@ -1108,6 +1113,7 @@ void security_fixup_ops (struct security_operations *ops)
1108 set_to_dummy_if_null(ops, sock_graft); 1113 set_to_dummy_if_null(ops, sock_graft);
1109 set_to_dummy_if_null(ops, inet_conn_request); 1114 set_to_dummy_if_null(ops, inet_conn_request);
1110 set_to_dummy_if_null(ops, inet_csk_clone); 1115 set_to_dummy_if_null(ops, inet_csk_clone);
1116 set_to_dummy_if_null(ops, inet_conn_established);
1111 set_to_dummy_if_null(ops, req_classify_flow); 1117 set_to_dummy_if_null(ops, req_classify_flow);
1112 #endif /* CONFIG_SECURITY_NETWORK */ 1118 #endif /* CONFIG_SECURITY_NETWORK */
1113#ifdef CONFIG_SECURITY_NETWORK_XFRM 1119#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 28ee187ed224..5bbd599a4471 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3535,8 +3535,10 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
3535 } 3535 }
3536 else if (isec->sclass == SECCLASS_TCP_SOCKET) { 3536 else if (isec->sclass == SECCLASS_TCP_SOCKET) {
3537 peer_sid = selinux_netlbl_socket_getpeersec_stream(sock); 3537 peer_sid = selinux_netlbl_socket_getpeersec_stream(sock);
3538 if (peer_sid == SECSID_NULL) 3538 if (peer_sid == SECSID_NULL) {
3539 peer_sid = selinux_socket_getpeer_stream(sock->sk); 3539 ssec = sock->sk->sk_security;
3540 peer_sid = ssec->peer_sid;
3541 }
3540 if (peer_sid == SECSID_NULL) { 3542 if (peer_sid == SECSID_NULL) {
3541 err = -ENOPROTOOPT; 3543 err = -ENOPROTOOPT;
3542 goto out; 3544 goto out;
@@ -3647,11 +3649,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3647 return 0; 3649 return 0;
3648 } 3650 }
3649 3651
3650 err = selinux_xfrm_decode_session(skb, &peersid, 0); 3652 selinux_skb_xfrm_sid(skb, &peersid);
3651 BUG_ON(err);
3652 3653
3653 if (peersid == SECSID_NULL) { 3654 if (peersid == SECSID_NULL) {
3654 req->secid = sksec->sid; 3655 req->secid = sksec->sid;
3656 req->peer_secid = 0;
3655 return 0; 3657 return 0;
3656 } 3658 }
3657 3659
@@ -3660,6 +3662,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3660 return err; 3662 return err;
3661 3663
3662 req->secid = newsid; 3664 req->secid = newsid;
3665 req->peer_secid = peersid;
3663 return 0; 3666 return 0;
3664} 3667}
3665 3668
@@ -3669,6 +3672,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
3669 struct sk_security_struct *newsksec = newsk->sk_security; 3672 struct sk_security_struct *newsksec = newsk->sk_security;
3670 3673
3671 newsksec->sid = req->secid; 3674 newsksec->sid = req->secid;
3675 newsksec->peer_sid = req->peer_secid;
3672 /* NOTE: Ideally, we should also get the isec->sid for the 3676 /* NOTE: Ideally, we should also get the isec->sid for the
3673 new socket in sync, but we don't have the isec available yet. 3677 new socket in sync, but we don't have the isec available yet.
3674 So we will wait until sock_graft to do it, by which 3678 So we will wait until sock_graft to do it, by which
@@ -3677,6 +3681,14 @@ static void selinux_inet_csk_clone(struct sock *newsk,
3677 selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family); 3681 selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family);
3678} 3682}
3679 3683
3684static void selinux_inet_conn_established(struct sock *sk,
3685 struct sk_buff *skb)
3686{
3687 struct sk_security_struct *sksec = sk->sk_security;
3688
3689 selinux_skb_xfrm_sid(skb, &sksec->peer_sid);
3690}
3691
3680static void selinux_req_classify_flow(const struct request_sock *req, 3692static void selinux_req_classify_flow(const struct request_sock *req,
3681 struct flowi *fl) 3693 struct flowi *fl)
3682{ 3694{
@@ -4739,6 +4751,7 @@ static struct security_operations selinux_ops = {
4739 .sock_graft = selinux_sock_graft, 4751 .sock_graft = selinux_sock_graft,
4740 .inet_conn_request = selinux_inet_conn_request, 4752 .inet_conn_request = selinux_inet_conn_request,
4741 .inet_csk_clone = selinux_inet_csk_clone, 4753 .inet_csk_clone = selinux_inet_csk_clone,
4754 .inet_conn_established = selinux_inet_conn_established,
4742 .req_classify_flow = selinux_req_classify_flow, 4755 .req_classify_flow = selinux_req_classify_flow,
4743 4756
4744#ifdef CONFIG_SECURITY_NETWORK_XFRM 4757#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 8e329ddb5e37..27502365d706 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -39,7 +39,6 @@ int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
39 struct avc_audit_data *ad); 39 struct avc_audit_data *ad);
40int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, 40int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
41 struct avc_audit_data *ad); 41 struct avc_audit_data *ad);
42u32 selinux_socket_getpeer_stream(struct sock *sk);
43u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); 42u32 selinux_socket_getpeer_dgram(struct sk_buff *skb);
44int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); 43int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
45#else 44#else
@@ -55,11 +54,6 @@ static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
55 return 0; 54 return 0;
56} 55}
57 56
58static inline int selinux_socket_getpeer_stream(struct sock *sk)
59{
60 return SECSID_NULL;
61}
62
63static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb) 57static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb)
64{ 58{
65 return SECSID_NULL; 59 return SECSID_NULL;
@@ -71,4 +65,10 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int
71} 65}
72#endif 66#endif
73 67
68static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
69{
70 int err = selinux_xfrm_decode_session(skb, sid, 0);
71 BUG_ON(err);
72}
73
74#endif /* _SELINUX_XFRM_H_ */ 74#endif /* _SELINUX_XFRM_H_ */
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 4d5a043cdfa1..8fef74271f22 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -184,7 +184,8 @@ int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
184} 184}
185 185
186/* 186/*
187 * LSM hook implementation that determines the sid for the session. 187 * LSM hook implementation that checks and/or returns the xfrm sid for the
188 * incoming packet.
188 */ 189 */
189 190
190int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) 191int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
@@ -403,43 +404,8 @@ void selinux_xfrm_state_free(struct xfrm_state *x)
403} 404}
404 405
405/* 406/*
406 * SELinux internal function to retrieve the context of a connected
407 * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security
408 * association used to connect to the remote socket.
409 *
410 * Retrieve via getsockopt SO_PEERSEC.
411 */
412u32 selinux_socket_getpeer_stream(struct sock *sk)
413{
414 struct dst_entry *dst, *dst_test;
415 u32 peer_sid = SECSID_NULL;
416
417 if (sk->sk_state != TCP_ESTABLISHED)
418 goto out;
419
420 dst = sk_dst_get(sk);
421 if (!dst)
422 goto out;
423
424 for (dst_test = dst; dst_test != 0;
425 dst_test = dst_test->child) {
426 struct xfrm_state *x = dst_test->xfrm;
427
428 if (x && selinux_authorizable_xfrm(x)) {
429 struct xfrm_sec_ctx *ctx = x->security;
430 peer_sid = ctx->ctx_sid;
431 break;
432 }
433 }
434 dst_release(dst);
435
436out:
437 return peer_sid;
438}
439
440/*
441 * SELinux internal function to retrieve the context of a UDP packet 407 * SELinux internal function to retrieve the context of a UDP packet
442 * based on its security association used to connect to the remote socket. 408 * based on its security association.
443 * 409 *
444 * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message 410 * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message
445 * type SCM_SECURITY. 411 * type SCM_SECURITY.