LWN.net Logo

New sock security patches

From:  Wayne Salamon <wsalamon@tislabs.com>
To:  <linux-security-module@wirex.com>
Subject:  New sock security patches
Date:  Thu, 29 Aug 2002 11:08:55 -0400 (EDT)


  Attached are two patches to support new functionality based on the sock
security structure. I've added a parameter to the
tcp_create_openreq_child() hook to add the listening sock.

  SELinux uses this change to label a new sock created from an accept()
call with the security label from the listening sock. Any packets sent
from the new sock before the user-space socket structure is attached will
be labeled correctly. Previously, these packets were labeled with a
default TCP socket SID.

  The SELinux post_create() hook was also changed to label a new sock with
the SID of the user-space socket. It is possible within the network stack
to have packets sent from a sock after being detached from the user
socket. These packets were previously labeled with the default TCP SID, but
now are labeled with the SID of the user socket.

  I've also attached, as separate patches, updates to LIDS and DTE for
this patch and the previous sock security patch.

  Wayne

-- 
Wayne Salamon
wsalamon@tislabs.com

Index: security/lids/lids_lsm.c
===================================================================
RCS file: /cvs/lsm/lsm-2.5/security/lids/lids_lsm.c,v
retrieving revision 1.18
diff -u -r1.18 lids_lsm.c
--- security/lids/lids_lsm.c	2002/08/16 13:29:40	1.18
+++ security/lids/lids_lsm.c	2002/08/29 14:45:48
@@ -848,13 +848,31 @@
 	return 0;
 }
 
+static int lids_socket_sock_alloc_security (struct sock *sk, int priority)
+{
+	return 0;
+}
+
+static void lids_socket_sock_free_security (struct sock *sk)
+{
+	return;
+}
+
 static int lids_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
 }
 
+static void lids_tcp_create_openreq_child(struct sock *sk,
+					 struct sock *newsk,
+					 struct sk_buff *skb)
+{
+	return;
+}
+
 static int lids_socket_unix_stream_connect (struct socket *sock,
-					     struct socket *other)
+					    struct socket *other,
+					    struct sock *newsk)
 {
 	return 0;
 }
@@ -1173,7 +1191,10 @@
 	socket_getsockopt:		lids_socket_getsockopt,
 	socket_setsockopt:		lids_socket_setsockopt,
 	socket_shutdown:		lids_socket_shutdown,
+	socket_sock_alloc_security:	lids_socket_sock_alloc_security,
+	socket_sock_free_security:	lids_socket_sock_free_security,
 	socket_sock_rcv_skb:		lids_sock_rcv_skb,
+	tcp_create_openreq_child:	lids_tcp_create_openreq_child,
 
 	skb_alloc_security:		lids_skb_alloc_security,
 	skb_clone:			lids_skb_clone,
Index: security/dte/dte.c
===================================================================
RCS file: /cvs/lsm/lsm-2.5/security/dte/dte.c,v
retrieving revision 1.16
diff -u -r1.16 dte.c
--- security/dte/dte.c	2002/08/01 19:36:32	1.16
+++ security/dte/dte.c	2002/08/29 14:45:48
@@ -690,13 +690,31 @@
 	return 0;
 }
 
+static int dte_socket_sock_alloc_security (struct sock *sk, int priority)
+{
+	return 0;
+}
+
+static void dte_socket_sock_free_security (struct sock *sk)
+{
+	return;
+}
+
 static int dte_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
 }
 
+static void dte_tcp_create_openreq_child(struct sock *sk,
+					 struct sock *newsk,
+					 struct sk_buff *skb)
+{
+	return;
+}
+
 static int dte_socket_unix_stream_connect (struct socket *sock,
-					   struct socket *other)
+					   struct socket *other,
+					   struct sock *newsk)
 {
 	return 0;
 }
@@ -1018,7 +1036,10 @@
 	socket_getsockopt:		dte_socket_getsockopt,
 	socket_setsockopt:		dte_socket_setsockopt,
 	socket_shutdown:		dte_socket_shutdown,
+	socket_sock_alloc_security:	dte_socket_sock_alloc_security,
+	socket_sock_free_security:	dte_socket_sock_free_security,
 	socket_sock_rcv_skb:		dte_sock_rcv_skb,
+	tcp_create_openreq_child:	dte_tcp_create_openreq_child,
 	
 	skb_alloc_security:		dte_skb_alloc_security,
 	skb_clone:			dte_skb_clone,
Index: lsm-2.5/include/linux/security.h
===================================================================
RCS file: /cvs/lsm/lsm-2.5/include/linux/security.h,v
retrieving revision 1.18
diff -u -r1.18 security.h
--- lsm-2.5/include/linux/security.h	2002/08/16 13:07:46	1.18
+++ lsm-2.5/include/linux/security.h	2002/08/28 13:19:20
@@ -694,9 +694,10 @@
  * 	Return 0 if permission is granted.
  * @tcp_create_openreq_child:
  *      A new connection is being established on a TCP sock. This hooks allows
- *      the association of peer security information with the new socket as
+ *      the association of security information with the new sock as it is
  *      it is being created.
- *      @sk contains the sock associated with the new connection.
+ *      @sk contains the listening sock.
+ *      @newsk contains the sock associated with the new connection.
  *      @skb contains the incoming network packet that finalized the connection.
  *
  * Lifecycle hooks for network buffers.
@@ -1330,7 +1331,7 @@
 	int (*socket_sock_alloc_security) (struct sock * sk, int priority);
 	void (*socket_sock_free_security) (struct sock * sk);
 	int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
-	void (*tcp_create_openreq_child) (struct sock * sk, 
+	void (*tcp_create_openreq_child) (struct sock * sk, struct sock * newsk,
 					  struct sk_buff * skb);
 
 	int (*skb_alloc_security) (struct sk_buff * skb);
Index: lsm-2.5/net/ipv4/tcp_minisocks.c
===================================================================
RCS file: /cvs/lsm/lsm-2.5/net/ipv4/tcp_minisocks.c,v
retrieving revision 1.2
diff -u -r1.2 tcp_minisocks.c
--- lsm-2.5/net/ipv4/tcp_minisocks.c	2002/08/16 13:07:47	1.2
+++ lsm-2.5/net/ipv4/tcp_minisocks.c	2002/08/28 13:19:20
@@ -790,7 +790,7 @@
 
 		TCP_INC_STATS_BH(TcpPassiveOpens);
 
-		security_ops->tcp_create_openreq_child(newsk, skb);
+		security_ops->tcp_create_openreq_child(sk, newsk, skb);
 	}
 	return newsk;
 }
Index: lsm-2.5/security/capability.c
===================================================================
RCS file: /cvs/lsm/lsm-2.5/security/capability.c,v
retrieving revision 1.17
diff -u -r1.17 capability.c
--- lsm-2.5/security/capability.c	2002/08/16 13:07:47	1.17
+++ lsm-2.5/security/capability.c	2002/08/28 13:19:20
@@ -869,7 +869,7 @@
 	return 0;
 }
 
-static void cap_tcp_create_openreq_child(struct sock *sk, 
+static void cap_tcp_create_openreq_child(struct sock *sk, struct sock *newsk,
 			 		 struct sk_buff *skb)
 {
 	return;
Index: lsm-2.5/security/dummy.c
===================================================================
RCS file: /cvs/lsm/lsm-2.5/security/dummy.c,v
retrieving revision 1.16
diff -u -r1.16 dummy.c
--- lsm-2.5/security/dummy.c	2002/08/16 13:07:47	1.16
+++ lsm-2.5/security/dummy.c	2002/08/28 13:19:20
@@ -686,7 +686,7 @@
 	return 0;
 }
 
-static void dummy_tcp_create_openreq_child(struct sock *sk, 
+static void dummy_tcp_create_openreq_child(struct sock *sk, struct sock *newsk, 
 					   struct sk_buff *skb)
 {
 	return;
Index: lsm-2.5/security/selinux/extsocket.h
===================================================================
RCS file: /cvs/lsm/lsm-2.5/security/selinux/extsocket.h,v
retrieving revision 1.6
diff -u -r1.6 extsocket.h
--- lsm-2.5/security/selinux/extsocket.h	2002/08/16 13:07:47	1.6
+++ lsm-2.5/security/selinux/extsocket.h	2002/08/28 13:19:20
@@ -29,85 +29,6 @@
 
 #ifdef CONFIG_SECURITY_SELINUX_EXTSOCKET
 
-/* 
- * Functions used to allocate/free sock security structures.
- */
-static LIST_HEAD(sock_security_head);
-static spinlock_t sock_alloc_lock = SPIN_LOCK_UNLOCKED;
-
-static inline int extsocket_sock_alloc_security(struct sock *sk)
-{
-	struct sock_security_struct *sksec, *new_sksec;
-	unsigned long flags;
-
-	new_sksec = kmalloc(sizeof(struct sock_security_struct), SAFE_ALLOC);
-	if (!new_sksec)
-		return -ENOMEM;
-
-	spin_lock_irqsave(&sock_alloc_lock, flags);
-	sksec = sk->security;
-	if (sksec && sksec->magic == SELINUX_MAGIC) {
-		spin_unlock_irqrestore(&sock_alloc_lock,flags);
-		kfree(new_sksec);
-		return 0;
-	}
-	sksec = new_sksec;
-
-	memset(sksec, 0, sizeof(struct sock_security_struct));
-	sksec->magic = SELINUX_MAGIC;
-	sksec->sk = sk;
-	list_add(&sksec->list, &sock_security_head);
-	sk->security = sksec;
-
-	spin_unlock_irqrestore(&sock_alloc_lock, flags);
-	return 0;
-}
-
-static inline void extsocket_sock_free_security(struct sock *sk)
-{
-	struct sock_security_struct *sksec;
-	unsigned long flags;
-
-	sksec = sk->security;
-	if (!sksec || sksec->magic != SELINUX_MAGIC)
-		return;
-
-	sk->security = NULL;
-	spin_lock_irqsave(&sock_alloc_lock, flags);
-	list_del(&sksec->list);
-	spin_unlock_irqrestore(&sock_alloc_lock, flags);
-	kfree(sksec);
-}
-
-static inline void extsocket_sock_free_security_all(void)
-{
-	struct list_head *p;
-	struct sock_security_struct *sksec;
-	p = sock_security_head.next;
-	while (p != &sock_security_head) {
-		sksec = list_entry(p, struct sock_security_struct, list);
-		p = p->next;
-		extsocket_sock_free_security(sksec->sk);
-        }
-
-}
-
-static inline int extsocket_sock_precondition(struct sock *sk)
-{
-	struct sock_security_struct *sksec;
-	int rc;
-
-	sksec = sk->security;
-	if (sksec && sksec->magic == SELINUX_MAGIC)
-		return 1;
-
-	rc = extsocket_sock_alloc_security(sk);
-	if (rc)
-		return rc;
-
-	return 1;
-}
-
 static inline void extsocket_init(struct inode_security_struct *isec)
 {
 	isec->peer_sid = SECINITSID_ANY_SOCKET;
@@ -250,7 +171,7 @@
 	if (err <= 0)
 		return;
 
-	err = extsocket_sock_precondition(sk);
+	err = sock_precondition(sk);
 	if (err <= 0)
 		return;
 
@@ -533,27 +454,25 @@
 	return 0;
 }
 
-static inline void extsocket_tcp_create_openreq_child(struct sock *sk,
-						      struct sk_buff *skb)
+static inline void extsocket_tcp_create_openreq_child(
+					struct sock_security_struct *newsksec,
+					struct inode_security_struct *isec,
+					struct sk_buff *skb)
 {
 	int err;
         struct skb_security_struct *skbsec;
-	struct sock_security_struct *sksec;
 
-	err = extsocket_sock_precondition(sk);
-	if (err <= 0)
-		return;
 	err = skb_precondition(skb);
 	if (err <= 0)
 		return;
-
 	skbsec = skb->lsm_security;
-	sksec = sk->security;
 
-	sksec->peer_sid = skbsec->ssid;
+	newsksec->peer_sid = skbsec->ssid;
 
-	return;
+	if (isec)
+		newsksec->sid = isec->newconn_sid;
 
+	return;
 }
 
 static inline int extsocket_unix_stream_connect(struct inode_security_struct *isec,
@@ -564,7 +483,7 @@
 	int err;
 	struct sock_security_struct *sksec;
 
-	err = extsocket_sock_precondition(newsk);
+	err = sock_precondition(newsk);
 	if (err <= 0)
 		return err;
 	sksec = newsk->security;
@@ -767,21 +686,6 @@
 	return;
 }
 
-static inline int extsocket_sock_alloc_security(struct sock *sk)
-{
-	return 0;
-}
-
-static inline void extsocket_sock_free_security(struct sock *sk)
-{
-	return;
-}
-
-static inline void extsocket_sock_free_security_all(void)
-{
-	return;
-}
-
 static inline int extsocket_sock_rcv_skb(struct sock *sk, 
 					 struct sk_buff *skb,
 					 struct inode_security_struct *isec,
@@ -791,8 +695,10 @@
 	return 0;
 }
 
-static inline void extsocket_tcp_create_openreq_child(struct sock *sk,
-						      struct sk_buff *skb)
+static inline void extsocket_tcp_create_openreq_child(
+					struct sock_security_struct *newsksec,
+					struct inode_security_struct *isec,
+					struct sk_buff *skb)
 {
 	return;
 }
Index: lsm-2.5/security/selinux/hooks.c
===================================================================
RCS file: /cvs/lsm/lsm-2.5/security/selinux/hooks.c,v
retrieving revision 1.91
diff -u -r1.91 hooks.c
--- lsm-2.5/security/selinux/hooks.c	2002/08/19 18:39:39	1.91
+++ lsm-2.5/security/selinux/hooks.c	2002/08/28 13:19:20
@@ -71,6 +71,7 @@
    Used to deallocate all security blobs and clear security 
    fields when the module exits. */
 static LIST_HEAD(task_security_head);
+static LIST_HEAD(sock_security_head);
 static LIST_HEAD(inode_security_head);
 static LIST_HEAD(file_security_head);
 static LIST_HEAD(msg_security_head);
@@ -127,6 +128,57 @@
 	kfree(tsec);
 }
 
+/* 
+ * Functions used to allocate/free sock security structures.
+ */
+static spinlock_t sock_alloc_lock = SPIN_LOCK_UNLOCKED;
+
+static int sock_alloc_security(struct sock *sk)
+{
+	struct sock_security_struct *sksec, *new_sksec;
+	unsigned long flags;
+
+	new_sksec = kmalloc(sizeof(struct sock_security_struct), SAFE_ALLOC);
+	if (!new_sksec)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&sock_alloc_lock, flags);
+	sksec = sk->security;
+	if (sksec && sksec->magic == SELINUX_MAGIC) {
+		spin_unlock_irqrestore(&sock_alloc_lock,flags);
+		kfree(new_sksec);
+		return 0;
+	}
+	sksec = new_sksec;
+
+	memset(sksec, 0, sizeof(struct sock_security_struct));
+	sksec->magic = SELINUX_MAGIC;
+	sksec->sk = sk;
+	list_add(&sksec->list, &sock_security_head);
+	sksec->sid = sksec->peer_sid = SECINITSID_UNLABELED;
+	sk->security = sksec;
+
+	spin_unlock_irqrestore(&sock_alloc_lock, flags);
+	return 0;
+}
+
+static void sock_free_security(struct sock *sk)
+{
+	struct sock_security_struct *sksec;
+	unsigned long flags;
+
+	sksec = sk->security;
+	if (!sksec || sksec->magic != SELINUX_MAGIC)
+		return;
+
+	sk->security = NULL;
+	spin_lock_irqsave(&sock_alloc_lock, flags);
+	list_del(&sksec->list);
+	spin_unlock_irqrestore(&sock_alloc_lock, flags);
+	kfree(sksec);
+}
+
+
 static spinlock_t inode_alloc_lock = SPIN_LOCK_UNLOCKED;
 
 static int inode_alloc_security(struct inode *inode)
@@ -563,6 +615,23 @@
 extern char * avc_d_path(struct dentry *dentry, 
 			 char *buffer, int buflen);
 
+/* The sock's security attributes must be initialized before first use. */
+int sock_precondition(struct sock *sk)
+{
+	struct sock_security_struct *sksec;
+	int rc;
+
+	sksec = sk->security;
+	if (sksec && sksec->magic == SELINUX_MAGIC)
+		return 1;
+
+	rc = sock_alloc_security(sk);
+	if (rc)
+		return rc;
+
+	return 1;
+}
+
 /* The inode's security attributes must be initialized before first use. */
 int inode_precondition(struct inode *inode) 
 {
@@ -3223,6 +3292,15 @@
 
 	isec->sid = extsocket_create(tsec);
 
+	/* Set the SID for the sock linked to the socket */
+	if(sock->sk) {
+		struct sock_security_struct *sksec;
+		err = sock_precondition(sock->sk);
+		if (err <= 0)
+			return;
+		sksec = sock->sk->security;
+		sksec->sid = isec->sid;
+	}
 	return;
 }
 
@@ -3565,12 +3643,12 @@
 
 static int selinux_socket_sock_alloc_security(struct sock *sk, int priority)
 {
-	return extsocket_sock_alloc_security(sk);
+	return sock_alloc_security(sk);
 }
 
 static void selinux_socket_sock_free_security(struct sock *sk)
 {
-	extsocket_sock_free_security(sk);
+	sock_free_security(sk);
 }
 
 static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
@@ -3683,9 +3761,36 @@
 }
 
 static void selinux_tcp_create_openreq_child(struct sock *sk, 
+					     struct sock *newsk,
 					     struct sk_buff *skb)
 {
-	extsocket_tcp_create_openreq_child(sk, skb);
+	struct inode_security_struct *isec = NULL;
+	struct sock_security_struct *newsksec;
+	int err;
+
+	err = sock_precondition(newsk);
+	if (err <= 0)
+		return;
+	newsksec = newsk->security;
+
+	/* 
+	 * If the existing (listening) sock has a socket structure, then
+	 * use it to obtain the security SID of the new sock. Otherwise,
+	 * use the default TCP socket SID, but this case shouldn't happen.
+	 */
+	if (sk->socket) {
+		err = inode_precondition(SOCK_INODE(sk->socket));
+		if (err <= 0) {
+			printk(__FUNCTION__ ": inode_precondition failed, err=%d\n", err);
+			return;
+		}
+		isec = SOCK_INODE(sk->socket)->i_security;
+		newsksec->sid = isec->sid;
+	} else {
+		newsksec->sid = SECINITSID_TCP_SOCKET;
+	}
+
+	extsocket_tcp_create_openreq_child(newsksec, isec, skb);
 }
 
 static int selinux_socket_unix_stream_connect(struct socket *sock, 
@@ -4475,6 +4580,7 @@
 {
 	struct skb_security_struct *ssec;
 	struct inode_security_struct *isec;
+	struct sock_security_struct *sksec;
 	int err;
 
 	err = skb_precondition(skb);
@@ -4482,10 +4588,15 @@
 		return;
 	ssec = skb->lsm_security;
 
+	err = sock_precondition(sk);
+	if (err <= 0)
+		return;
+	sksec = sk->security;
+
 	if (!sk->socket) {
 		if (sk->family == PF_INET && sk->type == SOCK_STREAM) {
 			/* TCP socket that has no associated user socket. */
-			ssec->ssid = SECINITSID_TCP_SOCKET;
+			ssec->ssid = sksec->sid;
 			ssec->msid = ssec->ssid;
 		} else if (sk->family == PF_INET) {
 			printk(__FUNCTION__ ":  no userspace socket (family %d, type %d, protocol %d)\n", sk->family, sk->type, sk->protocol);
@@ -4945,9 +5056,14 @@
 		p = p->next;
 		netdev_free_security(nsec->dev);
 	}
-
-	extsocket_sock_free_security_all();
 
+	p = sock_security_head.next;
+	while (p != &sock_security_head) {
+		struct sock_security_struct *sksec = list_entry(p, struct sock_security_struct, list);
+		p = p->next;
+		sock_free_security(sksec->sk);
+	}
+	
 	/* XXX:  Need AVC and security server interfaces for cleaning up. */
 		
 	printk (KERN_INFO "SELinux:  module removed\n");
Index: lsm-2.5/security/selinux/selinux_plug.h
===================================================================
RCS file: /cvs/lsm/lsm-2.5/security/selinux/selinux_plug.h,v
retrieving revision 1.20
diff -u -r1.20 selinux_plug.h
--- lsm-2.5/security/selinux/selinux_plug.h	2002/08/19 18:39:39	1.20
+++ lsm-2.5/security/selinux/selinux_plug.h	2002/08/28 13:19:20
@@ -37,14 +37,13 @@
         avc_entry_ref_t avcr;          /* reference to process permissions */
 };
 
-#ifdef CONFIG_SECURITY_SELINUX_EXTSOCKET
 struct sock_security_struct {
 	unsigned long magic;           /* magic number for this module */
 	struct sock *sk;               /* back pointer to sock object */
 	struct list_head list;         /* list of sock_security_struct */
+	security_id_t sid;             /* SID of the sock */
 	security_id_t peer_sid;        /* SID of the network peer */
 };
-#endif
 	
 struct inode_security_struct {
 	unsigned long magic;           /* magic number for this module */
@@ -203,6 +202,8 @@
 extern int superblock_precondition(struct super_block *sb);
 
 extern int skb_precondition(struct sk_buff *skb);
+
+extern int sock_precondition(struct sock *sk);
 
 /* Range of port numbers used to automatically bind.
    Need to determine whether we should perform a name_bind 
Index: security/lids/lids_lsm.c
===================================================================
RCS file: /cvs/lsm/lsm-2.4/security/lids/lids_lsm.c,v
retrieving revision 1.13
diff -u -r1.13 lids_lsm.c
--- security/lids/lids_lsm.c	2002/08/05 18:17:14	1.13
+++ security/lids/lids_lsm.c	2002/08/29 14:10:23
@@ -858,13 +858,31 @@
 	return 0;
 }
 
+static int lids_socket_sock_alloc_security (struct sock *sk, int priority)
+{
+	return 0;
+}
+
+static void lids_socket_sock_free_security (struct sock *sk)
+{
+	return;
+}
+
 static int lids_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
 }
 
+static void lids_tcp_create_openreq_child(struct sock *sk,
+					 struct sock *newsk,
+					 struct sk_buff *skb)
+{
+	return;
+}
+
 static int lids_socket_unix_stream_connect (struct socket *sock,
-					     struct socket *other)
+					    struct socket *other,
+					    struct sock *newsk)
 {
 	return 0;
 }
@@ -1184,7 +1202,10 @@
 	socket_getsockopt:		lids_socket_getsockopt,
 	socket_setsockopt:		lids_socket_setsockopt,
 	socket_shutdown:		lids_socket_shutdown,
+	socket_sock_alloc_security:	lids_socket_sock_alloc_security,
+	socket_sock_free_security:	lids_socket_sock_free_security,
 	socket_sock_rcv_skb:		lids_sock_rcv_skb,
+	tcp_create_openreq_child:	lids_tcp_create_openreq_child,
 
 	skb_alloc_security:		lids_skb_alloc_security,
 	skb_clone:			lids_skb_clone,
Index: security/dte/dte.c
===================================================================
RCS file: /cvs/lsm/lsm-2.4/security/dte/dte.c,v
retrieving revision 1.14
diff -u -r1.14 dte.c
--- security/dte/dte.c	2002/08/05 18:17:14	1.14
+++ security/dte/dte.c	2002/08/29 14:10:23
@@ -683,13 +683,31 @@
 	return 0;
 }
 
+static int dte_socket_sock_alloc_security (struct sock *sk, int priority)
+{
+	return 0;
+}
+
+static void dte_socket_sock_free_security (struct sock *sk)
+{
+	return;
+}
+
 static int dte_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
 }
 
+static void dte_tcp_create_openreq_child(struct sock *sk,
+					 struct sock *newsk,
+					 struct sk_buff *skb)
+{
+	return;
+}
+
 static int dte_socket_unix_stream_connect (struct socket *sock,
-					   struct socket *other)
+					   struct socket *other,
+					   struct sock *newsk)
 {
 	return 0;
 }
@@ -1006,7 +1024,10 @@
 	socket_getsockopt:		dte_socket_getsockopt,
 	socket_setsockopt:		dte_socket_setsockopt,
 	socket_shutdown:		dte_socket_shutdown,
+	socket_sock_alloc_security:	dte_socket_sock_alloc_security,
+	socket_sock_free_security:	dte_socket_sock_free_security,
 	socket_sock_rcv_skb:		dte_sock_rcv_skb,
+	tcp_create_openreq_child:	dte_tcp_create_openreq_child,
 	
 	skb_alloc_security:		dte_skb_alloc_security,
 	skb_clone:			dte_skb_clone,
Index: lsm-2.4/include/linux/security.h
===================================================================
RCS file: /cvs/lsm/lsm-2.4/include/linux/security.h,v
retrieving revision 1.109
diff -u -r1.109 security.h
--- lsm-2.4/include/linux/security.h	2002/08/16 12:44:44	1.109
+++ lsm-2.4/include/linux/security.h	2002/08/28 12:20:11
@@ -672,10 +672,11 @@
  *	@skb contains the incoming network data.
  * 	Return 0 if permission is granted.
  * @tcp_create_openreq_child:
- *      A new connection is being established on a sock. This hooks allows
- *      the association of peer security information with the new socket as
+ *      A new connection is being established on a TCP sock. This hooks allows
+ *      the association of security information with the new sock as it is
  *      it is being created.
- *      @sk contains the sock associated with the new connection.
+ *      @sk contains the listening sock.
+ *      @newsk contains the sock associated with the new connection.
  *      @skb contains the incoming network packet that finalized the connection.
  *
  * Lifecycle hooks for network buffers.
@@ -1328,7 +1329,7 @@
 	int (*socket_sock_alloc_security) (struct sock * sk, int priority);
 	void (*socket_sock_free_security) (struct sock * sk);
 	int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
-	void (*tcp_create_openreq_child) (struct sock * sk, 
+	void (*tcp_create_openreq_child) (struct sock * sk, struct sock * newsk,
 					  struct sk_buff * skb);
 
 	int (*skb_alloc_security) (struct sk_buff * skb);
Index: lsm-2.4/net/ipv4/tcp_minisocks.c
===================================================================
RCS file: /cvs/lsm/lsm-2.4/net/ipv4/tcp_minisocks.c,v
retrieving revision 1.2
diff -u -r1.2 tcp_minisocks.c
--- lsm-2.4/net/ipv4/tcp_minisocks.c	2002/08/16 12:44:44	1.2
+++ lsm-2.4/net/ipv4/tcp_minisocks.c	2002/08/28 12:20:12
@@ -786,7 +786,7 @@
 
 		TCP_INC_STATS_BH(TcpPassiveOpens);
 
-		security_ops->tcp_create_openreq_child(newsk, skb);
+		security_ops->tcp_create_openreq_child(sk, newsk, skb);
 	}
 	return newsk;
 }
Index: lsm-2.4/security/capability.c
===================================================================
RCS file: /cvs/lsm/lsm-2.4/security/capability.c,v
retrieving revision 1.15
diff -u -r1.15 capability.c
--- lsm-2.4/security/capability.c	2002/08/16 12:44:45	1.15
+++ lsm-2.4/security/capability.c	2002/08/28 12:20:12
@@ -857,7 +857,7 @@
 	return 0;
 }
 
-static void cap_tcp_create_openreq_child(struct sock *sk, 
+static void cap_tcp_create_openreq_child(struct sock *sk, struct sock *newsk,
 					 struct sk_buff *skb)
 {
 	return;
Index: lsm-2.4/security/dummy.c
===================================================================
RCS file: /cvs/lsm/lsm-2.4/security/dummy.c,v
retrieving revision 1.23
diff -u -r1.23 dummy.c
--- lsm-2.4/security/dummy.c	2002/08/16 12:44:45	1.23
+++ lsm-2.4/security/dummy.c	2002/08/28 12:20:12
@@ -675,7 +675,7 @@
 	return 0;
 }
 
-static void dummy_tcp_create_openreq_child(struct sock *sk, 
+static void dummy_tcp_create_openreq_child(struct sock *sk, struct sock *newsk,
 					   struct sk_buff *skb)
 {
 	return;
Index: lsm-2.4/security/selinux/extsocket.h
===================================================================
RCS file: /cvs/lsm/lsm-2.4/security/selinux/extsocket.h,v
retrieving revision 1.6
diff -u -r1.6 extsocket.h
--- lsm-2.4/security/selinux/extsocket.h	2002/08/16 12:44:45	1.6
+++ lsm-2.4/security/selinux/extsocket.h	2002/08/28 12:20:12
@@ -29,85 +29,6 @@
 
 #ifdef CONFIG_SECURITY_SELINUX_EXTSOCKET
 
-/* 
- * Functions used to allocate/free sock security structures.
- */
-static LIST_HEAD(sock_security_head);
-static spinlock_t sock_alloc_lock = SPIN_LOCK_UNLOCKED;
-
-static inline int extsocket_sock_alloc_security(struct sock *sk)
-{
-	struct sock_security_struct *sksec, *new_sksec;
-	unsigned long flags;
-
-	new_sksec = kmalloc(sizeof(struct sock_security_struct), SAFE_ALLOC);
-	if (!new_sksec)
-		return -ENOMEM;
-
-	spin_lock_irqsave(&sock_alloc_lock, flags);
-	sksec = sk->security;
-	if (sksec && sksec->magic == SELINUX_MAGIC) {
-		spin_unlock_irqrestore(&sock_alloc_lock,flags);
-		kfree(new_sksec);
-		return 0;
-	}
-	sksec = new_sksec;
-
-	memset(sksec, 0, sizeof(struct sock_security_struct));
-	sksec->magic = SELINUX_MAGIC;
-	sksec->sk = sk;
-	list_add(&sksec->list, &sock_security_head);
-	sk->security = sksec;
-
-	spin_unlock_irqrestore(&sock_alloc_lock, flags);
-	return 0;
-}
-
-static inline void extsocket_sock_free_security(struct sock *sk)
-{
-	struct sock_security_struct *sksec;
-	unsigned long flags;
-
-	sksec = sk->security;
-	if (!sksec || sksec->magic != SELINUX_MAGIC)
-		return;
-
-	sk->security = NULL;
-	spin_lock_irqsave(&sock_alloc_lock, flags);
-	list_del(&sksec->list);
-	spin_unlock_irqrestore(&sock_alloc_lock, flags);
-	kfree(sksec);
-}
-
-static inline void extsocket_sock_free_security_all(void)
-{
-	struct list_head *p;
-	struct sock_security_struct *sksec;
-	p = sock_security_head.next;
-	while (p != &sock_security_head) {
-		sksec = list_entry(p, struct sock_security_struct, list);
-		p = p->next;
-		extsocket_sock_free_security(sksec->sk);
-        }
-
-}
-
-static inline int extsocket_sock_precondition(struct sock *sk)
-{
-	struct sock_security_struct *sksec;
-	int rc;
-
-	sksec = sk->security;
-	if (sksec && sksec->magic == SELINUX_MAGIC)
-		return 1;
-
-	rc = extsocket_sock_alloc_security(sk);
-	if (rc)
-		return rc;
-
-	return 1;
-}
-
 static inline void extsocket_init(struct inode_security_struct *isec)
 {
 	isec->peer_sid = SECINITSID_ANY_SOCKET;
@@ -250,7 +171,7 @@
 	if (err <= 0)
 		return;
 
-	err = extsocket_sock_precondition(sk);
+	err = sock_precondition(sk);
 	if (err <= 0)
 		return;
 
@@ -259,7 +180,7 @@
 	isec = SOCK_INODE(sock)->i_security;
 	sksec = sk->security;
 
-	/* Set the peer SID of the new socket to the SID set in the 
+	/* Set the peer SID of the new socket to the SID set in the
 	 * new sock structure. This SID was set when the sock object
 	 * was created at final connection setup.
 	 */
@@ -532,27 +453,25 @@
 	return 0;
 }
 
-static inline void extsocket_tcp_create_openreq_child(struct sock *sk,
-						      struct sk_buff *skb)
+static inline void extsocket_tcp_create_openreq_child(
+					struct sock_security_struct *newsksec,
+					struct inode_security_struct *isec,
+					struct sk_buff *skb)
 {
 	int err;
         struct skb_security_struct *skbsec;
-	struct sock_security_struct *sksec;
 
-	err = extsocket_sock_precondition(sk);
-	if (err <= 0)
-		return;
 	err = skb_precondition(skb);
 	if (err <= 0)
 		return;
+	skbsec = skb->lsm_security;
 
-        skbsec = skb->lsm_security;
-	sksec = sk->security;
-
-	sksec->peer_sid = skbsec->ssid;
+	newsksec->peer_sid = skbsec->ssid;
 
-        return;
+	if (isec && isec->newconn_sid)
+		newsksec->sid = isec->newconn_sid;
 
+	return;
 }
 
 static inline int extsocket_unix_stream_connect(struct inode_security_struct *isec,
@@ -563,7 +482,7 @@
 	int err;
 	struct sock_security_struct *sksec;
 
-	err = extsocket_sock_precondition(newsk);
+	err = sock_precondition(newsk);
 	if (err <= 0)
 		return err;
 	sksec = newsk->security;
@@ -766,21 +685,6 @@
 	return;
 }
 
-static inline int extsocket_sock_alloc_security(struct sock *sk)
-{
-	return 0;
-}
-
-static inline void extsocket_sock_free_security(struct sock *sk)
-{
-	return;
-}
-
-static inline void extsocket_sock_free_security_all(void)
-{
-	return;
-}
-
 static inline int extsocket_sock_rcv_skb(struct sock *sk, 
 					 struct sk_buff *skb,
 					 struct inode_security_struct *isec,
@@ -790,8 +694,10 @@
 	return 0;
 }
 
-static inline void extsocket_tcp_create_openreq_child(struct sock *sk,
-						      struct sk_buff *skb)
+static inline void extsocket_tcp_create_openreq_child(
+					struct sock_security_struct *newsksec,
+					struct inode_security_struct *isec,
+					struct sk_buff *skb)
 {
 	return;
 }
Index: lsm-2.4/security/selinux/hooks.c
===================================================================
RCS file: /cvs/lsm/lsm-2.4/security/selinux/hooks.c,v
retrieving revision 1.93
diff -u -r1.93 hooks.c
--- lsm-2.4/security/selinux/hooks.c	2002/08/19 18:31:06	1.93
+++ lsm-2.4/security/selinux/hooks.c	2002/08/28 12:20:12
@@ -69,6 +69,7 @@
    Used to deallocate all security blobs and clear security 
    fields when the module exits. */
 static LIST_HEAD(task_security_head);
+static LIST_HEAD(sock_security_head);
 static LIST_HEAD(inode_security_head);
 static LIST_HEAD(file_security_head);
 static LIST_HEAD(msg_security_head);
@@ -125,6 +126,56 @@
 	kfree(tsec);
 }
 
+/* 
+ * Functions used to allocate/free sock security structures.
+ */
+static spinlock_t sock_alloc_lock = SPIN_LOCK_UNLOCKED;
+
+static int sock_alloc_security(struct sock *sk)
+{
+	struct sock_security_struct *sksec, *new_sksec;
+	unsigned long flags;
+
+	new_sksec = kmalloc(sizeof(struct sock_security_struct), SAFE_ALLOC);
+	if (!new_sksec)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&sock_alloc_lock, flags);
+	sksec = sk->security;
+	if (sksec && sksec->magic == SELINUX_MAGIC) {
+		spin_unlock_irqrestore(&sock_alloc_lock,flags);
+		kfree(new_sksec);
+		return 0;
+	}
+	sksec = new_sksec;
+
+	memset(sksec, 0, sizeof(struct sock_security_struct));
+	sksec->magic = SELINUX_MAGIC;
+	sksec->sk = sk;
+	list_add(&sksec->list, &sock_security_head);
+	sksec->sid = sksec->peer_sid = SECINITSID_UNLABELED;
+	sk->security = sksec;
+
+	spin_unlock_irqrestore(&sock_alloc_lock, flags);
+	return 0;
+}
+
+static void sock_free_security(struct sock *sk)
+{
+	struct sock_security_struct *sksec;
+	unsigned long flags;
+
+	sksec = sk->security;
+	if (!sksec || sksec->magic != SELINUX_MAGIC)
+		return;
+
+	sk->security = NULL;
+	spin_lock_irqsave(&sock_alloc_lock, flags);
+	list_del(&sksec->list);
+	spin_unlock_irqrestore(&sock_alloc_lock, flags);
+	kfree(sksec);
+}
+
 static spinlock_t inode_alloc_lock = SPIN_LOCK_UNLOCKED;
 
 static int inode_alloc_security(struct inode *inode)
@@ -561,6 +612,23 @@
 extern char * avc_d_path(struct dentry *dentry, 
 			 char *buffer, int buflen);
 
+/* The sock's security attributes must be initialized before first use. */
+int sock_precondition(struct sock *sk)
+{
+	struct sock_security_struct *sksec;
+	int rc;
+
+	sksec = sk->security;
+	if (sksec && sksec->magic == SELINUX_MAGIC)
+		return 1;
+
+	rc = sock_alloc_security(sk);
+	if (rc)
+		return rc;
+
+	return 1;
+}
+
 /* The inode's security attributes must be initialized before first use. */
 int inode_precondition(struct inode *inode) 
 {
@@ -3179,6 +3247,15 @@
 
 	isec->sid = extsocket_create(tsec);
 
+	/* Set the SID for the sock linked to the socket */
+	if(sock->sk) {
+		struct sock_security_struct *sksec;
+		err = sock_precondition(sock->sk);
+		if (err <= 0)
+			return;
+		sksec = sock->sk->security;
+		sksec->sid = isec->sid;
+	}
 	return;
 }
 
@@ -3521,12 +3598,12 @@
 
 static int selinux_socket_sock_alloc_security(struct sock *sk, int priority)
 {
-	return extsocket_sock_alloc_security(sk);
+	return sock_alloc_security(sk);
 }
 
 static void selinux_socket_sock_free_security(struct sock *sk)
 {
-	extsocket_sock_free_security(sk);
+	sock_free_security(sk);
 }
 
 static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
@@ -3639,9 +3716,36 @@
 }
 
 static void selinux_tcp_create_openreq_child(struct sock *sk, 
+					     struct sock *newsk,
 					     struct sk_buff *skb)
 {
-	extsocket_tcp_create_openreq_child(sk, skb);
+	struct inode_security_struct *isec = NULL;
+	struct sock_security_struct *newsksec;
+	int err;
+
+	err = sock_precondition(newsk);
+	if (err <= 0)
+		return;
+	newsksec = newsk->security;
+
+	/* 
+	 * If the existing (listening) sock has a socket structure, then
+	 * use it to obtain the security SID of the new sock. Otherwise,
+	 * use the default TCP socket SID, but this case shouldn't happen.
+	 */
+	if (sk->socket) {
+		err = inode_precondition(SOCK_INODE(sk->socket));
+		if (err <= 0) {
+			printk(__FUNCTION__ ": inode_precondition failed, err=%d\n", err);
+			return;
+		}
+		isec = SOCK_INODE(sk->socket)->i_security;
+		newsksec->sid = isec->sid;
+	} else {
+		newsksec->sid = SECINITSID_TCP_SOCKET;
+	}
+
+	extsocket_tcp_create_openreq_child(newsksec, isec, skb);
 }
 
 static int selinux_socket_unix_stream_connect(struct socket *sock, 
@@ -4430,6 +4534,7 @@
 {
 	struct skb_security_struct *ssec;
 	struct inode_security_struct *isec;
+	struct sock_security_struct *sksec;
 	int err;
 
 	err = skb_precondition(skb);
@@ -4437,10 +4542,15 @@
 		return;
 	ssec = skb->lsm_security;
 
+	err = sock_precondition(sk);
+	if (err <= 0)
+		return;
+	sksec = sk->security;
+
 	if (!sk->socket) {
 		if (sk->family == PF_INET && sk->type == SOCK_STREAM) {
 			/* TCP socket that has no associated user socket. */
-			ssec->ssid = SECINITSID_TCP_SOCKET;
+			ssec->ssid = sksec->sid;
 			ssec->msid = ssec->ssid;
 		} else if (sk->family == PF_INET) {
 			printk(__FUNCTION__ ":  no userspace socket (family %d, type %d, protocol %d)\n", sk->family, sk->type, sk->protocol);
@@ -4903,7 +5013,12 @@
 		netdev_free_security(nsec->dev);
 	}
 
-	extsocket_sock_free_security_all();
+	p = sock_security_head.next;
+	while (p != &sock_security_head) {
+		struct sock_security_struct *sksec = list_entry(p, struct sock_security_struct, list);
+		p = p->next;
+		sock_free_security(sksec->sk);
+        }
 
 	/* XXX:  Need AVC and security server interfaces for cleaning up. */
 		
Index: lsm-2.4/security/selinux/selinux_plug.h
===================================================================
RCS file: /cvs/lsm/lsm-2.4/security/selinux/selinux_plug.h,v
retrieving revision 1.20
diff -u -r1.20 selinux_plug.h
--- lsm-2.4/security/selinux/selinux_plug.h	2002/08/19 18:31:06	1.20
+++ lsm-2.4/security/selinux/selinux_plug.h	2002/08/28 12:20:12
@@ -37,14 +37,13 @@
         avc_entry_ref_t avcr;          /* reference to process permissions */
 };
 
-#ifdef CONFIG_SECURITY_SELINUX_EXTSOCKET
 struct sock_security_struct {
 	unsigned long magic;           /* magic number for this module */
 	struct sock *sk;               /* back pointer to sock object */
 	struct list_head list;         /* list of sock_security_struct */
+	security_id_t sid;             /* SID of the sock */
 	security_id_t peer_sid;        /* SID of the network peer */
 };
-#endif
 	
 struct inode_security_struct {
 	unsigned long magic;           /* magic number for this module */
@@ -203,6 +202,8 @@
 extern int superblock_precondition(struct super_block *sb);
 
 extern int skb_precondition(struct sk_buff *skb);
+
+extern int sock_precondition(struct sock *sk);
 
 /* Range of port numbers used to automatically bind.
    Need to determine whether we should perform a name_bind 

Copyright © 2002, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds