[redhat-lspp] [PATCH] lsm-secpeer for IPSec labels

George Wilson ltcgcw at us.ibm.com
Wed Sep 14 00:40:51 UTC 2005


Attached is Trent Jaeger's patch that adds a getsockopt() to obtain the label
from an labeled IPSec connection.  It depends on Trent's IPSec implicit network
labels patch posted to netdev.  Trent's comments precede the actual patch, and
should provide enough information to get you going.  Once the base patch is
upstream, this patch will be submitted to netdev.  Please help flush out the
bugs and post your results

-- 
George Wilson <ltcgcw at us.ibm.com>
IBM Linux Technology Center
-------------- next part --------------

This patch implements an application of the LSM-IPSec networking 
controls whereby an application can determine the label of the 
security association its TCP sockets are currently connected to via
getsockopt.  

Patch purpose:

This patch enables a security-aware application to retrieve the
security context of an IPSec security association a particular TCP
socket is using.  The application can then use this security context
to determine the security context for processing on behalf of the peer
at the other end of this connection.  For example, inetd could be
modified to start daemons running at security contexts dependent on
the remote client.

Patch design approach:

The patch enables the SELinux LSM to set the peer security context for
a socket based on the security context of the IPSec security
association.  The application may retrieve this context using
getsockopt.  When called, the kernel determines if the socket is a
connected (TCP_ESTABLISHED) TCP socket and, if so, uses the dst_entry
cache on the socket to retrieve the security associations.  If a
security association has a security context, the context string is
returned, as for UNIX domain sockets.

Patch implementation details: 

The security context can be retrieved by applications using getsockopt
with the existing SO_PEERSEC flag.  As an example (ignoring error
checking):

getsockopt(sockfd, SOL_SOCKET, SO_PEERSEC, optbuf, &optlen);
printf("Socket peer context is: %s\n", optbuf);

The SELinux function, selinux_socket_getpeersec, is extended to check
for labelled security associations for connected (TCP_ESTABLISHED ==
sk->sk_state) TCP sockets only.  If so, the socket has a dst_cache of
struct dst_entry values that may refer to security associations.  If
these have security associations with security contexts, the security
context is returned.  

getsockopt returns a buffer than contains a security context string or 
the buffer is unmodified. 

Testing:

We have tested the patch by setting up TCP connections between
applications on two machines using the IPSec policies that result in
labelled security associations being built.  We can then extract the
peer security context using getsockopt on either end.




---

 security/selinux/hooks.c        |   24 ++++++++++++++++++++----
 security/selinux/include/xfrm.h |    1 +
 security/selinux/xfrm.c         |   29 ++++++++++++++++++++++++++++-
 3 files changed, 49 insertions(+), 5 deletions(-)

diff -puN security/selinux/hooks.c~lsm-secpeer-nethooks security/selinux/hooks.c
--- linux-2.6.13-rc3-git4-xfrm/security/selinux/hooks.c~lsm-secpeer-nethooks	2005-07-18 12:11:12.000000000 -0400
+++ linux-2.6.13-rc3-git4-xfrm-root/security/selinux/hooks.c	2005-07-18 12:11:12.000000000 -0400
@@ -267,8 +267,10 @@ static int sk_alloc_security(struct sock
 {
 	struct sk_security_struct *ssec;
 
+#if 0
 	if (family != PF_UNIX)
 		return 0;
+#endif
 
 	ssec = kmalloc(sizeof(*ssec), priority);
 	if (!ssec)
@@ -3389,16 +3391,30 @@ static int selinux_socket_getpeersec(str
 	u32 scontext_len;
 	struct sk_security_struct *ssec;
 	struct inode_security_struct *isec;
+	u32 peer_sid = 0;
 
 	isec = SOCK_INODE(sock)->i_security;
-	if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
+
+	/* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */
+	if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) {
+		ssec = sock->sk->sk_security;
+		peer_sid = ssec->peer_sid;
+	}
+	else if (isec->sclass == SECCLASS_TCP_SOCKET) {
+		peer_sid = selinux_socket_getpeer(sock->sk);
+
+		if (!peer_sid) {
+			err = -ENOPROTOOPT;
+			goto out;
+		}
+	}
+	else {
 		err = -ENOPROTOOPT;
 		goto out;
 	}
 
-	ssec = sock->sk->sk_security;
-	
-	err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
+	err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
+
 	if (err)
 		goto out;
 
diff -puN security/selinux/include/xfrm.h~lsm-secpeer-nethooks security/selinux/include/xfrm.h
--- linux-2.6.13-rc3-git4-xfrm/security/selinux/include/xfrm.h~lsm-secpeer-nethooks	2005-07-18 12:11:12.000000000 -0400
+++ linux-2.6.13-rc3-git4-xfrm-root/security/selinux/include/xfrm.h	2005-07-18 12:11:12.000000000 -0400
@@ -14,6 +14,7 @@ void selinux_xfrm_state_free(struct xfrm
 int selinux_xfrm_policy_lookup(struct sock *sk, struct xfrm_policy *xp, struct flowi *fl, u8 dir);
 int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb);
 int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb);
+u32 selinux_socket_getpeer(struct sock *sk);
 
 #endif /* _SELINUX_XFRM_H_ */
 
diff -puN security/selinux/xfrm.c~lsm-secpeer-nethooks security/selinux/xfrm.c
--- linux-2.6.13-rc3-git4-xfrm/security/selinux/xfrm.c~lsm-secpeer-nethooks	2005-07-18 12:11:12.000000000 -0400
+++ linux-2.6.13-rc3-git4-xfrm-root/security/selinux/xfrm.c	2005-07-18 12:11:12.000000000 -0400
@@ -157,7 +157,7 @@ out:
  * Security blob allocation for xfrm_policy and xfrm_state
  * CTX does not have a meaningful value on input
  */
-static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
+static inline int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
 {
 	int rc = 0;
 	struct task_security_struct *tsec = current->security;
@@ -309,6 +309,33 @@ 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(struct sock *sk)
+{
+	struct dst_entry *dst = __sk_dst_get(sk);
+	struct dst_entry *dst_test;
+
+	if (sk->sk_state != TCP_ESTABLISHED) return 0;
+	if (!dst) return 0;
+
+	for (dst_test = dst; dst_test != 0;
+	     dst_test = dst_test->child) {
+		struct xfrm_state *x = dst_test->xfrm;
+
+		if (selinux_authorizable_xfrm(x)) {
+			struct xfrm_sec_ctx *ctx = xfrm_state_security(x);
+			return ctx->ctx_sid;
+		}
+	}
+	return 0;
+}
+
+/*
  * LSM hook that controls access to unlabelled packets.  If
  * a xfrm_state is authorizable (defined by macro) then it was
  * already authorized by the IPSec process.  If not, then


More information about the redhat-lspp mailing list