Patch: Socket hooks

From: Chris Vance (cvanceat_private)
Date: Fri Jul 20 2001 - 12:19:12 PDT

  • Next message: Chris Vance: "Re: Patch: Socket hooks"

    Attached is a patch for review.  It contains hooks to implement
    socket-level security checks.  The patch was generated from our cvs
    repository, but should apply cleanly against the July 6 LSM tree (2.4.6
    kernel).
    
    This patch makes no attempts to secure skbuffs or network devices.  We are
    still working towards an implementation that is most likely to be accepted
    by the kernel folks. To that end, we are going to see what we can do with
    the netfilter code rather than directly modifying the ip input/ouput
    routines or modifying the sk_buff structure (which apparently would be
    difficult to gain approval for).  If anyone has any relevant insight, I
    would welcome it.  
    
    What it does do is provide hooks for:
    	create & post_create	bind
    	connect			listen
    	accept			sendmsg
    	recvmsg			getsockname
    	getpeername		getsockopt
    	setsockopt		shutdown
    
    In the cases of connect and accept, SELinux is likely to need something
    more than the hooks provided here.  I'm still looking into the best way to
    do what we need.
    
    chris.
    
    
    Index: include/linux/netdevice.h
    ===================================================================
    RCS file: /cvs/lsm/lsm/include/linux/netdevice.h,v
    retrieving revision 1.1.1.1
    retrieving revision 1.2
    diff -u -r1.1.1.1 -r1.2
    --- include/linux/netdevice.h	2001/06/11 18:19:59	1.1.1.1
    +++ include/linux/netdevice.h	2001/07/17 18:12:01	1.2
    @@ -291,6 +291,7 @@
     	unsigned short		type;	/* interface hardware type	*/
     	unsigned short		hard_header_len;	/* hardware hdr length	*/
     	void			*priv;	/* pointer to private data	*/
    +	void			*d_security; /* device security block   */
     
     	struct net_device	*master; /* Pointer to master device of a group,
     					  * which this device is member of.
    Index: include/linux/security.h
    ===================================================================
    RCS file: /cvs/lsm/lsm/include/linux/security.h,v
    retrieving revision 1.19
    diff -u -r1.19 security.h
    --- include/linux/security.h	2001/07/06 19:39:42	1.19
    +++ include/linux/security.h	2001/07/20 18:55:49
    @@ -116,11 +116,23 @@
     	int (* setscheduler)		(struct task_struct *p, int policy);
     	int (* kill)			(struct task_struct *p, struct siginfo *info, int sig);
     	int (* wait)			(struct task_struct *p);
    -	
     	void (* kmod_set_label)	        (void);
     };
     
     struct socket_security_ops {
    +	int (* create)			(int family, int type, int protocol);
    +	void (* post_create)		(struct socket *sock, int family, int type, int protocol);
    +	int (* bind)			(struct socket *sock, struct sockaddr *address, int addrlen);
    +	int (* connect)			(struct socket *sock, struct sockaddr *address, int addrlen);
    +	int (* listen)			(struct socket *sock, int backlog);
    +	int (* accept)			(struct socket *sock, struct socket *newsock, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
    +	int (* sendmsg)			(struct socket *sock, struct msghdr *msg, int size);
    +	int (* recvmsg)			(struct socket *sock, struct msghdr *msg, int size, int flags);
    +	int (* getsockname)		(struct socket *sock);
    +	int (* getpeername)		(struct socket *sock);
    +	int (* getsockopt)		(struct socket *sock, int level, int optname);
    +	int (* setsockopt)		(struct socket *sock, int level, int optname, char *optval, int optlen);
    +	int (* shutdown)		(struct socket *sock, int how);
     };
     
     struct module_security_ops {
    Index: kernel/capability_plug.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/kernel/capability_plug.c,v
    retrieving revision 1.7
    retrieving revision 1.11
    diff -u -r1.7 -r1.11
    --- kernel/capability_plug.c	2001/07/06 19:39:42	1.7
    +++ kernel/capability_plug.c	2001/07/20 18:32:06	1.11
    @@ -56,6 +56,7 @@
     
     static int cap_setcapablity	(void)	{return 0;}
     static int cap_acct		(struct file *file) {return 0;}
    +static int cap_sysctl		(ctl_table * table, int op) {return 0;}
     
     static int cap_binprm_alloc_security(struct linux_binprm *bprm)
     {
    @@ -290,6 +291,20 @@
     	return;
     }
     
    +static int cap_socket_create	(int family, int type, int protocol) {return 0;}
    +static void cap_socket_post_create	(struct socket *sock, int family, int type, int protocol) {return;}
    +static int cap_socket_bind	(struct socket *sock, struct sockaddr *address, int addrlen) {return 0;}
    +static int cap_socket_connect	(struct socket *sock, struct sockaddr *address, int addrlen) {return 0;}
    +static int cap_socket_listen	(struct socket *sock, int backlog) {return 0;}
    +static int cap_socket_accept(	struct socket *sock, struct socket *newsock, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) {return 0;}
    +static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) {return 0;}
    +static int cap_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) {return 0;}
    +static int cap_socket_getsockname	(struct socket *sock) {return 0;}
    +static int cap_socket_getpeername	(struct socket *sock) {return 0;}
    +static int cap_socket_setsockopt	(struct socket *sock, int level, int optname, char *optval, int optlen) {return 0;}
    +static int cap_socket_getsockopt	(struct socket *sock, int level, int optname) {return 0;}
    +static int cap_socket_shutdown	(struct socket *sock, int how) {return 0;}
    +
     static int cap_module_create_module	(const char *name_user, size_t size)			{return 0;}
     static int cap_module_init_module	(const char *name_user, struct module *mod_user)	{return 0;}
     static int cap_module_delete_module	(const char *name_user)					{return 0;}
    @@ -396,7 +411,21 @@
     	kmod_set_label:	cap_task_kmod_set_label,
     };
     
    -static struct socket_security_ops cap_socket_ops = {};
    +static struct socket_security_ops cap_socket_ops = {
    +	create:		cap_socket_create,
    +	post_create:	cap_socket_post_create,
    +	bind:		cap_socket_bind,
    +	connect:	cap_socket_connect,
    +	listen:		cap_socket_listen,
    +	accept:		cap_socket_accept,
    +	sendmsg:	cap_socket_sendmsg,
    +	recvmsg:	cap_socket_recvmsg,
    +	getsockname:	cap_socket_getsockname,
    +	getpeername:	cap_socket_getpeername,
    +	getsockopt:	cap_socket_getsockopt,
    +	setsockopt:	cap_socket_setsockopt,
    +	shutdown:	cap_socket_shutdown,
    +};
     
     static struct module_security_ops cap_module_ops = {
     	create_module:	cap_module_create_module,
    @@ -458,6 +487,7 @@
     	ptrace:			cap_ptrace,
     	setcapability:		cap_setcapablity,
     	acct:			cap_acct,
    +	sysctl:			cap_sysctl,
     	capable:		cap_capable,
     
     	bprm_ops:		&cap_binprm_ops,
    Index: kernel/security.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/kernel/security.c,v
    retrieving revision 1.20
    retrieving revision 1.25
    diff -u -r1.20 -r1.25
    --- kernel/security.c	2001/07/06 19:39:42	1.20
    +++ kernel/security.c	2001/07/20 18:32:06	1.25
    @@ -127,6 +127,21 @@
     
     static void dummy_task_kmod_set_label	(void)	                {return;}
     
    +static int dummy_socket_create(int family, int type, int protocol) {return 0;}
    +static void dummy_socket_post_create(struct socket *sock, int family, int type, int protocol) {return;} 
    +static int dummy_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) {return 0;}
    +static int dummy_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) {return 0;}
    +static int dummy_socket_listen(struct socket *sock, int backlog) {return 0;}
    +static int dummy_socket_accept(struct socket *sock, struct socket *newsock, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) {return 0;}
    +static int dummy_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) {return 0;}
    +static int dummy_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) {return 0;}
    +static int dummy_socket_getsockname(struct socket *sock) {return 0;}
    +static int dummy_socket_getpeername(struct socket *sock) {return 0;}
    +static int dummy_socket_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) {return 0;}
    +static int dummy_socket_getsockopt(struct socket *sock, int level, int optname) {return 0;}
    +static int dummy_socket_shutdown(struct socket *sock, int how) {return 0;}
    +
    +
     static int dummy_module_create_module	(const char *name_user, size_t size)			{return 0;}
     static int dummy_module_init_module	(const char *name_user, struct module *mod_user)	{return 0;}
     static int dummy_module_delete_module	(const char *name_user)					{return 0;}
    @@ -233,7 +248,21 @@
     	kmod_set_label:	dummy_task_kmod_set_label,
     };
     
    -static struct socket_security_ops dummy_socket_ops = {};
    +static struct socket_security_ops dummy_socket_ops = {
    +	create:			dummy_socket_create,
    +	post_create:		dummy_socket_post_create,
    +	bind:			dummy_socket_bind,
    +	connect:		dummy_socket_connect,
    +	listen:			dummy_socket_listen,
    +	accept:			dummy_socket_accept,
    +	sendmsg:		dummy_socket_sendmsg,
    +	recvmsg:		dummy_socket_recvmsg,
    +	getsockname:		dummy_socket_getsockname,
    +	getpeername:		dummy_socket_getpeername,
    +	getsockopt:		dummy_socket_getsockopt,
    +	setsockopt:		dummy_socket_setsockopt,
    +	shutdown:		dummy_socket_shutdown,
    +};
     
     static struct module_security_ops dummy_module_ops = {
     	create_module:	dummy_module_create_module,
    Index: net/socket.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/net/socket.c,v
    retrieving revision 1.1.1.2
    retrieving revision 1.4
    diff -u -r1.1.1.2 -r1.4
    --- net/socket.c	2001/06/18 19:26:34	1.1.1.2
    +++ net/socket.c	2001/07/20 18:15:25	1.4
    @@ -507,6 +507,10 @@
     	int err;
     	struct scm_cookie scm;
     
    +	err = security_ops->socket_ops->sendmsg(sock, msg, size);
    +	if (err)
    +		return err;
    +
     	err = scm_send(sock, msg, &scm);
     	if (err >= 0) {
     		err = sock->ops->sendmsg(sock, msg, size, &scm);
    @@ -518,6 +522,11 @@
     int sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags)
     {
     	struct scm_cookie scm;
    +	int err;
    +
    +	err = security_ops->socket_ops->recvmsg(sock, msg, size, flags);
    +	if (err)
    +		return err;
     
     	memset(&scm, 0, sizeof(scm));
     
    @@ -836,6 +845,7 @@
     int sock_create(int family, int type, int protocol, struct socket **res)
     {
     	int i;
    +	int err;
     	struct socket *sock;
     
     	/*
    @@ -857,6 +867,13 @@
     		}
     		family = PF_PACKET;
     	}
    +
    +	/*
    +	 * Don't even allow modules to be loaded if this fails.
    +	 */
    +	err = security_ops->socket_ops->create(family, type, protocol);
    +	if (err)
    +		return err;
     		
     #if defined(CONFIG_KMOD) && defined(CONFIG_NET)
     	/* Attempt to load a protocol module if the find failed. 
    @@ -903,6 +920,8 @@
     
     	*res = sock;
     
    +	security_ops->socket_ops->post_create(sock, family, type, protocol);
    +
     out:
     	net_family_read_unlock();
     	return i;
    @@ -1012,8 +1031,14 @@
     
     	if((sock = sockfd_lookup(fd,&err))!=NULL)
     	{
    -		if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0)
    +		if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
    +			err = security_ops->socket_ops->bind(sock, (struct sockaddr *)address, addrlen);
    +			if (err) {
    +				sockfd_put(sock);
    +				return err;
    +			}
     			err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
    +		}
     		sockfd_put(sock);
     	}			
     	return err;
    @@ -1034,6 +1059,13 @@
     	if ((sock = sockfd_lookup(fd, &err)) != NULL) {
     		if ((unsigned) backlog > SOMAXCONN)
     			backlog = SOMAXCONN;
    +
    +		err = security_ops->socket_ops->listen(sock, backlog);
    +		if (err) {
    +			sockfd_put(sock);
    +			return err;
    +		}
    +
     		err=sock->ops->listen(sock, backlog);
     		sockfd_put(sock);
     	}
    @@ -1070,6 +1102,11 @@
     	newsock->type = sock->type;
     	newsock->ops = sock->ops;
     
    +	err = security_ops->socket_ops->accept(sock, newsock, upeer_sockaddr,
    +					       upeer_addrlen);
    +	if (err)
    +		goto out_release;
    +
     	err = sock->ops->accept(sock, newsock, sock->file->f_flags);
     	if (err < 0)
     		goto out_release;
    @@ -1124,8 +1161,14 @@
     	err = move_addr_to_kernel(uservaddr, addrlen, address);
     	if (err < 0)
     		goto out_put;
    +
    +	err = security_ops->socket_ops->connect(sock, (struct sockaddr *)address, addrlen);
    +	if (err)
    +		goto out_put;
    +
     	err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
     				 sock->file->f_flags);
    +
     out_put:
     	sockfd_put(sock);
     out:
    @@ -1146,6 +1189,11 @@
     	sock = sockfd_lookup(fd, &err);
     	if (!sock)
     		goto out;
    +
    +	err = security_ops->socket_ops->getsockname(sock);
    +	if (err)
    +		goto out_put;
    +
     	err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 0);
     	if (err)
     		goto out_put;
    @@ -1170,6 +1218,12 @@
     
     	if ((sock = sockfd_lookup(fd, &err))!=NULL)
     	{
    +		err = security_ops->socket_ops->getpeername(sock);
    +		if (err) {
    +			sockfd_put(sock);
    +			return err;
    +		}
    +
     		err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
     		if (!err)
     			err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
    @@ -1297,6 +1351,14 @@
     			
     	if ((sock = sockfd_lookup(fd, &err))!=NULL)
     	{
    +		err = security_ops->socket_ops->setsockopt(sock, level, 
    +							   optname, optval, 
    +							   optlen);
    +		if (err) {
    +			sockfd_put(sock);
    +			return err;
    +		}
    +
     		if (level == SOL_SOCKET)
     			err=sock_setsockopt(sock,level,optname,optval,optlen);
     		else
    @@ -1318,6 +1380,13 @@
     
     	if ((sock = sockfd_lookup(fd, &err))!=NULL)
     	{
    +		err = security_ops->socket_ops->getsockopt(sock, level, 
    +							   optname);
    +		if (err) {
    +			sockfd_put(sock);
    +			return err;
    +		}
    +
     		if (level == SOL_SOCKET)
     			err=sock_getsockopt(sock,level,optname,optval,optlen);
     		else
    @@ -1339,6 +1408,12 @@
     
     	if ((sock = sockfd_lookup(fd, &err))!=NULL)
     	{
    +		err = security_ops->socket_ops->shutdown(sock, how);
    +		if (err) {
    +			sockfd_put(sock);
    +			return err;
    +		}
    +				
     		err=sock->ops->shutdown(sock, how);
     		sockfd_put(sock);
     	}
    
    _______________________________________________
    linux-security-module mailing list
    linux-security-moduleat_private
    http://mail.wirex.com/mailman/listinfo/linux-security-module
    



    This archive was generated by hypermail 2b30 : Fri Jul 20 2001 - 12:23:10 PDT