[PATCH] LSM networking update: socket_sock_rcv_skb() hook (3/5)

From: James Morris (jmorrisat_private)
Date: Thu Feb 06 2003 - 07:17:39 PST

  • Next message: Christoph Hellwig: "Re: [BK PATCH] LSM changes for 2.5.59"

     include/linux/security.h |   18 ++++++++
     include/net/sock.h       |   95 +++++++++++++++++++++++++++++++----------------
     net/decnet/dn_nsp_in.c   |   29 +++++---------
     net/ipv4/tcp_ipv4.c      |    9 +---
     net/ipv6/tcp_ipv6.c      |   15 +++----
     net/sctp/input.c         |    4 +
     security/dummy.c         |    5 ++
     7 files changed, 112 insertions(+), 63 deletions(-)
    
    diff -urN -X dontdiff linux-2.5.59.w0/include/linux/security.h linux-2.5.59.w1/include/linux/security.h
    --- linux-2.5.59.w0/include/linux/security.h	Fri Feb  7 01:29:51 2003
    +++ linux-2.5.59.w1/include/linux/security.h	Fri Feb  7 01:16:22 2003
    @@ -684,6 +684,12 @@
      *	@sock contains the socket structure.
      *	@how contains the flag indicating how future sends and receives are handled.
      *	Return 0 if permission is granted.
    + * @socket_sock_rcv_skb:
    + *	Check permissions on incoming network packets.  This hook is distinct
    + *	from Netfilter's IP input hooks since it is the first time that the
    + *	incoming sk_buff @skb has been associated with a particular socket, @sk.
    + *	@sk contains the sock (not socket) associated with the incoming sk_buff.
    + *	@skb contains the incoming network data.
      *
      * Security hooks affecting all System V IPC operations.
      *
    @@ -1073,6 +1079,7 @@
     	int (*socket_getsockopt) (struct socket * sock, int level, int optname);
     	int (*socket_setsockopt) (struct socket * sock, int level, int optname);
     	int (*socket_shutdown) (struct socket * sock, int how);
    +	int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
     #endif	/* CONFIG_SECURITY_NETWORK */
     };
     
    @@ -2312,6 +2319,12 @@
     {
     	return security_ops->socket_shutdown(sock, how);
     }
    +
    +static inline int security_sock_rcv_skb (struct sock * sk, 
    +					 struct sk_buff * skb)
    +{
    +	return security_ops->socket_sock_rcv_skb (sk, skb);
    +}
     #else	/* CONFIG_SECURITY_NETWORK */
     static inline int security_socket_create (int family, int type, int protocol)
     {
    @@ -2394,6 +2407,11 @@
     {
     	return 0;
     }
    +static inline int security_sock_rcv_skb (struct sock * sk, 
    +					 struct sk_buff * skb)
    +{
    +	return 0;
    +}
     #endif	/* CONFIG_SECURITY_NETWORK */
     
     #endif /* ! __LINUX_SECURITY_H */
    diff -urN -X dontdiff linux-2.5.59.w0/include/net/sock.h linux-2.5.59.w1/include/net/sock.h
    --- linux-2.5.59.w0/include/net/sock.h	Fri Feb  7 01:29:51 2003
    +++ linux-2.5.59.w1/include/net/sock.h	Fri Feb  7 01:18:37 2003
    @@ -44,6 +44,7 @@
     
     #include <linux/netdevice.h>
     #include <linux/skbuff.h>	/* struct sk_buff */
    +#include <linux/security.h>
     
     #ifdef CONFIG_FILTER
     #include <linux/filter.h>
    @@ -458,28 +459,45 @@
     #ifdef CONFIG_FILTER
     
     /**
    - *	sk_filter - run a packet through a socket filter
    + *	__sk_filter - run a packet through a socket filter
    + *	@sk: sock associated with &sk_buff
      *	@skb: buffer to filter
    - *	@filter: filter to apply
    + *	@needlock: set to 1 if the sock is not locked by caller.
      *
      * Run the filter code and then cut skb->data to correct size returned by
      * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
      * than pkt_len we keep whole skb->data. This is the socket level
      * wrapper to sk_run_filter. It returns 0 if the packet should
    - * be accepted or 1 if the packet should be tossed.
    + * be accepted or -EPERM if the packet should be tossed.
    + *
    + * This function should not be called directly, use sk_filter instead
    + * to ensure that the LSM security check is also performed.
      */
    - 
    -static inline int sk_filter(struct sk_buff *skb, struct sk_filter *filter)
    +
    +static inline int __sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
     {
    -	int pkt_len;
    +	int err = 0;
     
    -        pkt_len = sk_run_filter(skb, filter->insns, filter->len);
    -        if(!pkt_len)
    -                return 1;	/* Toss Packet */
    -        else
    -                skb_trim(skb, pkt_len);
    +	if (sk->filter) {
    +		struct sk_filter *filter;
    +		
    +		if (needlock)
    +			bh_lock_sock(sk);
    +		
    +		filter = sk->filter;
    +		if (filter) {
    +			int pkt_len = sk_run_filter(skb, filter->insns,
    +						    filter->len);
    +			if (!pkt_len)
    +				err = -EPERM;
    +			else
    +				skb_trim(skb, pkt_len);
    +		}
     
    -	return 0;
    +		if (needlock)
    +			bh_unlock_sock(sk);
    +	}
    +	return err;
     }
     
     /**
    @@ -506,8 +524,26 @@
     	atomic_add(sk_filter_len(fp), &sk->omem_alloc);
     }
     
    +#else
    +
    +static inline int __sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
    +{
    +	return 0;
    +}
    +
     #endif /* CONFIG_FILTER */
     
    +static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
    +{
    +	int err;
    +	
    +	err = security_sock_rcv_skb(sk, skb);
    +	if (err)
    +		return err;
    +	
    +	return __sk_filter(sk, skb, needlock);
    +}
    +
     /*
      * Socket reference counting postulates.
      *
    @@ -712,36 +748,31 @@
     
     static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
     {
    +	int err = 0;
    +
     	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
     	   number of warnings when compiling with -W --ANK
     	 */
    -	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
    -                return -ENOMEM;
    -
    -#ifdef CONFIG_FILTER
    -	if (sk->filter) {
    -		int err = 0;
    -		struct sk_filter *filter;
    -
    -		/* It would be deadlock, if sock_queue_rcv_skb is used
    -		   with socket lock! We assume that users of this
    -		   function are lock free.
    -		 */
    -		bh_lock_sock(sk);
    -		if ((filter = sk->filter) != NULL && sk_filter(skb, filter))
    -			err = -EPERM;
    -		bh_unlock_sock(sk);
    -		if (err)
    -			return err;	/* Toss packet */
    +	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) {
    +		err = -ENOMEM;
    +		goto out;
     	}
    -#endif /* CONFIG_FILTER */
    +
    +	/* It would be deadlock, if sock_queue_rcv_skb is used
    +	   with socket lock! We assume that users of this
    +	   function are lock free.
    +	*/
    +	err = sk_filter(sk, skb, 1);
    +	if (err)
    +		goto out;
     
     	skb->dev = NULL;
     	skb_set_owner_r(skb, sk);
     	skb_queue_tail(&sk->receive_queue, skb);
     	if (!sk->dead)
     		sk->data_ready(sk,skb->len);
    -	return 0;
    +out:
    +	return err;
     }
     
     static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
    diff -urN -X dontdiff linux-2.5.59.w0/net/decnet/dn_nsp_in.c linux-2.5.59.w1/net/decnet/dn_nsp_in.c
    --- linux-2.5.59.w0/net/decnet/dn_nsp_in.c	Fri Feb  7 01:29:51 2003
    +++ linux-2.5.59.w1/net/decnet/dn_nsp_in.c	Fri Feb  7 01:16:22 2003
    @@ -566,26 +566,19 @@
      */
     static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue)
     {
    -#ifdef CONFIG_FILTER
    -	struct sk_filter *filter;
    -#endif
    -
    +	int err;
    +	
             /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
                number of warnings when compiling with -W --ANK
              */
    -        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf
    -)
    -                return -ENOMEM;
    -
    -#ifdef CONFIG_FILTER
    -        if (sk->filter) {
    -		int err = 0;
    -                if ((filter = sk->filter) != NULL && sk_filter(skb, sk->filter))
    -                        err = -EPERM;  /* Toss packet */
    -		if (err)
    -			return err;
    +        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) {
    +        	err = -ENOMEM;
    +        	goto out;
             }
    -#endif /* CONFIG_FILTER */
    +
    +	err = sk_filter(sk, skb, 0);
    +	if (err)
    +		goto out;
     
             skb_set_owner_r(skb, sk);
             skb_queue_tail(queue, skb);
    @@ -603,8 +596,8 @@
     				    (sig == SIGURG) ? POLL_PRI : POLL_IN);
     	}
     	read_unlock(&sk->callback_lock);
    -
    -        return 0;
    +out:
    +        return err;
     }
     
     static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
    diff -urN -X dontdiff linux-2.5.59.w0/net/ipv4/tcp_ipv4.c linux-2.5.59.w1/net/ipv4/tcp_ipv4.c
    --- linux-2.5.59.w0/net/ipv4/tcp_ipv4.c	Fri Feb  7 01:29:51 2003
    +++ linux-2.5.59.w1/net/ipv4/tcp_ipv4.c	Fri Feb  7 01:16:22 2003
    @@ -1696,12 +1696,6 @@
      */
     int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
     {
    -#ifdef CONFIG_FILTER
    -	struct sk_filter *filter = sk->filter;
    -	if (filter && sk_filter(skb, filter))
    -		goto discard;
    -#endif /* CONFIG_FILTER */
    -
     	if (sk->state == TCP_ESTABLISHED) { /* Fast path */
     		TCP_CHECK_TIMER(sk);
     		if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
    @@ -1804,6 +1798,9 @@
     	if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb))
     		goto discard_and_relse;
     
    +	if (sk_filter(sk, skb, 0))
    +		goto discard_and_relse;
    +
     	skb->dev = NULL;
     
     	bh_lock_sock(sk);
    diff -urN -X dontdiff linux-2.5.59.w0/net/ipv6/tcp_ipv6.c linux-2.5.59.w1/net/ipv6/tcp_ipv6.c
    --- linux-2.5.59.w0/net/ipv6/tcp_ipv6.c	Fri Feb  7 01:29:51 2003
    +++ linux-2.5.59.w1/net/ipv6/tcp_ipv6.c	Fri Feb  7 01:16:22 2003
    @@ -1470,9 +1470,6 @@
     {
     	struct ipv6_pinfo *np = inet6_sk(sk);
     	struct tcp_opt *tp;
    -#ifdef CONFIG_FILTER
    -	struct sk_filter *filter;
    -#endif
     	struct sk_buff *opt_skb = NULL;
     
     	/* Imagine: socket is IPv6. IPv4 packet arrives,
    @@ -1486,11 +1483,8 @@
     	if (skb->protocol == htons(ETH_P_IP))
     		return tcp_v4_do_rcv(sk, skb);
     
    -#ifdef CONFIG_FILTER
    -	filter = sk->filter;
    -	if (filter && sk_filter(skb, filter))
    +	if (sk_filter(sk, skb, 0))
     		goto discard;
    -#endif /* CONFIG_FILTER */
     
     	/*
     	 *	socket locking is here for SMP purposes as backlog rcv
    @@ -1641,6 +1635,9 @@
     	if(sk->state == TCP_TIME_WAIT)
     		goto do_time_wait;
     
    +	if (sk_filter(sk, skb, 0))
    +		goto discard_and_relse;
    +
     	skb->dev = NULL;
     
     	bh_lock_sock(sk);
    @@ -1672,6 +1669,10 @@
     	kfree_skb(skb);
     	return 0;
     
    +discard_and_relse:
    +	sock_put(sk);
    +	goto discard_it;
    +                
     do_time_wait:
     	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
     		TCP_INC_STATS_BH(TcpInErrs);
    diff -urN -X dontdiff linux-2.5.59.w0/net/sctp/input.c linux-2.5.59.w1/net/sctp/input.c
    --- linux-2.5.59.w0/net/sctp/input.c	Fri Feb  7 01:29:51 2003
    +++ linux-2.5.59.w1/net/sctp/input.c	Fri Feb  7 01:27:49 2003
    @@ -159,6 +159,10 @@
     	if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb))
     		goto discard_release;
     
    +	ret = sk_filter(sk, skb, 1);
    +	if (ret)
    +                goto discard_release;
    +
     	/* Create an SCTP packet structure. */
     	chunk = sctp_chunkify(skb, asoc, sk);
     	if (!chunk) {
    diff -urN -X dontdiff linux-2.5.59.w0/security/dummy.c linux-2.5.59.w1/security/dummy.c
    --- linux-2.5.59.w0/security/dummy.c	Fri Feb  7 01:29:51 2003
    +++ linux-2.5.59.w1/security/dummy.c	Fri Feb  7 01:16:22 2003
    @@ -674,6 +674,10 @@
     	return 0;
     }
     
    +static int dummy_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
    +{
    +	return 0;
    +}
     #endif	/* CONFIG_SECURITY_NETWORK */
     
     static int dummy_register_security (const char *name, struct security_operations *ops)
    @@ -819,6 +823,7 @@
     	set_to_dummy_if_null(ops, socket_setsockopt);
     	set_to_dummy_if_null(ops, socket_getsockopt);
     	set_to_dummy_if_null(ops, socket_shutdown);
    +	set_to_dummy_if_null(ops, socket_sock_rcv_skb);
     #endif	/* CONFIG_SECURITY_NETWORK */
     }
     
    
    
    _______________________________________________
    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 : Thu Feb 06 2003 - 07:20:21 PST