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>
This commit is contained in:
parent
c1a856c964
commit
6b877699c6
|
@ -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,9 +2964,15 @@ static inline void security_inet_csk_clone(struct sock *newsk,
|
|||
{
|
||||
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,
|
||||
struct socket * other,
|
||||
struct sock * newsk)
|
||||
{
|
||||
return 0;
|
||||
|
@ -3110,6 +3119,11 @@ static inline void security_inet_csk_clone(struct sock *newsk,
|
|||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -4230,6 +4230,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
|
|||
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);
|
||||
|
||||
|
|
|
@ -828,6 +828,11 @@ static inline void dummy_inet_csk_clone(struct sock *newsk,
|
|||
{
|
||||
}
|
||||
|
||||
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_operations *ops)
|
|||
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
|
||||
|
|
|
@ -3535,8 +3535,10 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
|
|||
}
|
||||
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;
|
||||
|
@ -3647,11 +3649,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -3660,6 +3662,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
|||
return err;
|
||||
|
||||
req->secid = newsid;
|
||||
req->peer_secid = peersid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3669,6 +3672,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
|
|||
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
|
||||
|
@ -3677,6 +3681,14 @@ static void selinux_inet_csk_clone(struct sock *newsk,
|
|||
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)
|
||||
{
|
||||
|
@ -4739,6 +4751,7 @@ static struct security_operations selinux_ops = {
|
|||
.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
|
||||
|
|
|
@ -39,7 +39,6 @@ int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
|
|||
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_last(u32 isec_sid, struct sk_buff *skb,
|
|||
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_session(struct sk_buff *skb, u32 *sid, int
|
|||
}
|
||||
#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_ */
|
||||
|
|
|
@ -184,7 +184,8 @@ int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
|
|||
}
|
||||
|
||||
/*
|
||||
* 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,44 +403,9 @@ void selinux_xfrm_state_free(struct xfrm_state *x)
|
|||
kfree(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
|
Loading…
Reference in New Issue