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 <[EMAIL PROTECTED]> --- include/linux/security.h | 14 ++++++++++ include/net/request_sock.h | 1 net/ipv4/tcp_input.c | 2 + security/dummy.c | 6 ++++ security/selinux/hooks.c | 21 ++++++++++++--- security/selinux/include/xfrm.h | 12 ++++----- security/selinux/xfrm.c | 40 ++---------------------------- 7 files changed, 49 insertions(+), 47 deletions(-) --- net-2.6.xfrm1/include/linux/security.h 2006-10-25 09:34:47.000000000 -0500 +++ net-2.6.xfrm2/include/linux/security.h 2006-10-25 12:26:20.000000000 -0500 @@ -826,6 +826,8 @@ struct request_sock; * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid. * @inet_csk_clone: * Sets the new child socket's sid to the openreq sid. + * @inet_conn_established: + * Sets the connection's peersid to the secmark on skb. * @req_classify_flow: * Sets the flow's sid to the openreq sid. * @@ -1368,6 +1370,7 @@ struct security_operations { int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb, struct request_sock *req); void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req); + void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb); void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl); #endif /* CONFIG_SECURITY_NETWORK */ @@ -2961,6 +2964,12 @@ static inline void security_inet_csk_clo { security_ops->inet_csk_clone(newsk, req); } + +static inline void security_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ + security_ops->inet_conn_established(sk, skb); +} #else /* CONFIG_SECURITY_NETWORK */ static inline int security_unix_stream_connect(struct socket * sock, struct socket * other, @@ -3110,6 +3119,11 @@ static inline void security_inet_csk_clo const struct request_sock *req) { } + +static inline void security_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ +} #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM --- net-2.6.xfrm1/include/net/request_sock.h 2006-10-25 11:20:48.000000000 -0500 +++ net-2.6.xfrm2/include/net/request_sock.h 2006-10-25 11:21:56.000000000 -0500 @@ -54,6 +54,7 @@ struct request_sock { struct request_sock_ops *rsk_ops; struct sock *sk; u32 secid; + u32 peer_secid; }; static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) --- net-2.6.xfrm1/net/ipv4/tcp_input.c 2006-10-25 12:29:06.000000000 -0500 +++ net-2.6.xfrm2/net/ipv4/tcp_input.c 2006-10-25 12:30:07.000000000 -0500 @@ -4230,6 +4230,8 @@ static int tcp_rcv_synsent_state_process mb(); tcp_set_state(sk, TCP_ESTABLISHED); + security_inet_conn_established(sk, skb); + /* Make sure socket is routed, for correct metrics. */ icsk->icsk_af_ops->rebuild_header(sk); --- net-2.6.xfrm1/security/dummy.c 2006-10-23 14:31:28.000000000 -0500 +++ net-2.6.xfrm2/security/dummy.c 2006-10-25 12:23:47.000000000 -0500 @@ -828,6 +828,11 @@ static inline void dummy_inet_csk_clone( { } +static inline void dummy_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ +} + static inline void dummy_req_classify_flow(const struct request_sock *req, struct flowi *fl) { @@ -1108,6 +1113,7 @@ void security_fixup_ops (struct security set_to_dummy_if_null(ops, sock_graft); set_to_dummy_if_null(ops, inet_conn_request); set_to_dummy_if_null(ops, inet_csk_clone); + set_to_dummy_if_null(ops, inet_conn_established); set_to_dummy_if_null(ops, req_classify_flow); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM --- net-2.6.xfrm1/security/selinux/include/xfrm.h 2006-10-23 14:31:56.000000000 -0500 +++ net-2.6.xfrm2/security/selinux/include/xfrm.h 2006-11-07 09:49:24.000000000 -0600 @@ -39,7 +39,6 @@ int selinux_xfrm_sock_rcv_skb(u32 sid, s struct avc_audit_data *ad); int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, struct avc_audit_data *ad); -u32 selinux_socket_getpeer_stream(struct sock *sk); u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); #else @@ -55,11 +54,6 @@ static inline int selinux_xfrm_postroute return 0; } -static inline int selinux_socket_getpeer_stream(struct sock *sk) -{ - return SECSID_NULL; -} - static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb) { return SECSID_NULL; @@ -71,4 +65,10 @@ static inline int selinux_xfrm_decode_se } #endif +static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid) +{ + int err = selinux_xfrm_decode_session(skb, sid, 0); + BUG_ON(err); +} + #endif /* _SELINUX_XFRM_H_ */ --- net-2.6.xfrm1/security/selinux/hooks.c 2006-10-25 11:50:15.000000000 -0500 +++ net-2.6.xfrm2/security/selinux/hooks.c 2006-11-07 09:51:10.000000000 -0600 @@ -3528,8 +3528,10 @@ static int selinux_socket_getpeersec_str } else if (isec->sclass == SECCLASS_TCP_SOCKET) { peer_sid = selinux_netlbl_socket_getpeersec_stream(sock); - if (peer_sid == SECSID_NULL) - peer_sid = selinux_socket_getpeer_stream(sock->sk); + if (peer_sid == SECSID_NULL) { + ssec = sock->sk->sk_security; + peer_sid = ssec->peer_sid; + } if (peer_sid == SECSID_NULL) { err = -ENOPROTOOPT; goto out; @@ -3640,11 +3642,11 @@ static int selinux_inet_conn_request(str return 0; } - err = selinux_xfrm_decode_session(skb, &peersid, 0); - BUG_ON(err); + selinux_skb_xfrm_sid(skb, &peersid); if (peersid == SECSID_NULL) { req->secid = sksec->sid; + req->peer_secid = 0; return 0; } @@ -3653,6 +3655,7 @@ static int selinux_inet_conn_request(str return err; req->secid = newsid; + req->peer_secid = peersid; return 0; } @@ -3662,6 +3665,7 @@ static void selinux_inet_csk_clone(struc struct sk_security_struct *newsksec = newsk->sk_security; newsksec->sid = req->secid; + newsksec->peer_sid = req->peer_secid; /* NOTE: Ideally, we should also get the isec->sid for the new socket in sync, but we don't have the isec available yet. So we will wait until sock_graft to do it, by which @@ -3670,6 +3674,14 @@ static void selinux_inet_csk_clone(struc selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family); } +static void selinux_inet_conn_established(struct sock *sk, + struct sk_buff *skb) +{ + struct sk_security_struct *sksec = sk->sk_security; + + selinux_skb_xfrm_sid(skb, &sksec->peer_sid); +} + static void selinux_req_classify_flow(const struct request_sock *req, struct flowi *fl) { @@ -4732,6 +4744,7 @@ static struct security_operations selinu .sock_graft = selinux_sock_graft, .inet_conn_request = selinux_inet_conn_request, .inet_csk_clone = selinux_inet_csk_clone, + .inet_conn_established = selinux_inet_conn_established, .req_classify_flow = selinux_req_classify_flow, #ifdef CONFIG_SECURITY_NETWORK_XFRM --- net-2.6.xfrm1/security/selinux/xfrm.c 2006-10-23 14:30:02.000000000 -0500 +++ net-2.6.xfrm2/security/selinux/xfrm.c 2006-11-07 09:49:47.000000000 -0600 @@ -184,7 +184,8 @@ int selinux_xfrm_flow_state_match(struct } /* - * LSM hook implementation that determines the sid for the session. + * LSM hook implementation that checks and/or returns the xfrm sid for the + * incoming packet. */ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) @@ -402,43 +403,8 @@ void selinux_xfrm_state_free(struct xfrm } /* - * SELinux internal function to retrieve the context of a connected - * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security - * association used to connect to the remote socket. - * - * Retrieve via getsockopt SO_PEERSEC. - */ -u32 selinux_socket_getpeer_stream(struct sock *sk) -{ - struct dst_entry *dst, *dst_test; - u32 peer_sid = SECSID_NULL; - - if (sk->sk_state != TCP_ESTABLISHED) - goto out; - - dst = sk_dst_get(sk); - if (!dst) - goto out; - - for (dst_test = dst; dst_test != 0; - dst_test = dst_test->child) { - struct xfrm_state *x = dst_test->xfrm; - - if (x && selinux_authorizable_xfrm(x)) { - struct xfrm_sec_ctx *ctx = x->security; - peer_sid = ctx->ctx_sid; - break; - } - } - dst_release(dst); - -out: - return peer_sid; -} - -/* * SELinux internal function to retrieve the context of a UDP packet - * based on its security association used to connect to the remote socket. + * based on its security association. * * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message * type SCM_SECURITY. - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html