diff options
author | Venkat Yekkirala <vyekkirala@trustedcs.com> | 2006-11-08 18:04:09 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:21:33 -0500 |
commit | 6b877699c6f1efede4545bcecc367786a472eedb (patch) | |
tree | c0a60dc90578fa9f16d4496e2700bc285eab47c0 | |
parent | c1a856c9640c9ff3d70bbd8214b6a0974609eef8 (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.h | 16 | ||||
-rw-r--r-- | include/net/request_sock.h | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 2 | ||||
-rw-r--r-- | security/dummy.c | 6 | ||||
-rw-r--r-- | security/selinux/hooks.c | 21 | ||||
-rw-r--r-- | security/selinux/include/xfrm.h | 12 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 40 |
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 | |||
2968 | static 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 */ |
2965 | static inline int security_unix_stream_connect(struct socket * sock, | 2974 | static 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 | |||
3123 | static 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 | ||
59 | static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) | 60 | static 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 | ||
831 | static inline void dummy_inet_conn_established(struct sock *sk, | ||
832 | struct sk_buff *skb) | ||
833 | { | ||
834 | } | ||
835 | |||
831 | static inline void dummy_req_classify_flow(const struct request_sock *req, | 836 | static 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 | ||
3684 | static 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 | |||
3680 | static void selinux_req_classify_flow(const struct request_sock *req, | 3692 | static 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); |
40 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 40 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
41 | struct avc_audit_data *ad); | 41 | struct avc_audit_data *ad); |
42 | u32 selinux_socket_getpeer_stream(struct sock *sk); | ||
43 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); | 42 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); |
44 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); | 43 | int 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 | ||
58 | static inline int selinux_socket_getpeer_stream(struct sock *sk) | ||
59 | { | ||
60 | return SECSID_NULL; | ||
61 | } | ||
62 | |||
63 | static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb) | 57 | static 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 | ||
68 | static 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 | ||
190 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | 191 | int 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 | */ | ||
412 | u32 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 | |||
436 | out: | ||
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. |