]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - include/net/sock.h
[NET]: Fix sk->sk_filter field access
[linux-2.6-omap-h63xx.git] / include / net / sock.h
index 0969fb60d6ea6b5e6396c42600943f8070060f46..edd4d73ce7f5cb4371430942bc542c4c72df84a1 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/timer.h>
 #include <linux/cache.h>
 #include <linux/module.h>
+#include <linux/lockdep.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>      /* struct sk_buff */
 #include <linux/security.h>
@@ -78,18 +79,17 @@ typedef struct {
        spinlock_t              slock;
        struct sock_iocb        *owner;
        wait_queue_head_t       wq;
+       /*
+        * We express the mutex-alike socket_lock semantics
+        * to the lock validator by explicitly managing
+        * the slock as a lock variant (in addition to
+        * the slock itself):
+        */
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map dep_map;
+#endif
 } socket_lock_t;
 
-extern struct lock_class_key af_family_keys[AF_MAX];
-
-#define sock_lock_init(__sk) \
-do {   spin_lock_init(&((__sk)->sk_lock.slock)); \
-       lockdep_set_class(&(__sk)->sk_lock.slock, \
-                         af_family_keys + (__sk)->sk_family); \
-       (__sk)->sk_lock.owner = NULL; \
-       init_waitqueue_head(&((__sk)->sk_lock.wq)); \
-} while(0)
-
 struct sock;
 struct proto;
 
@@ -862,30 +862,24 @@ extern void sock_init_data(struct socket *sock, struct sock *sk);
  *
  */
 
-static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
+static inline int sk_filter(struct sock *sk, struct sk_buff *skb)
 {
        int err;
+       struct sk_filter *filter;
        
        err = security_sock_rcv_skb(sk, skb);
        if (err)
                return err;
        
-       if (sk->sk_filter) {
-               struct sk_filter *filter;
-               
-               if (needlock)
-                       bh_lock_sock(sk);
-               
-               filter = sk->sk_filter;
-               if (filter) {
-                       unsigned int pkt_len = sk_run_filter(skb, filter->insns,
-                                                            filter->len);
-                       err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
-               }
-
-               if (needlock)
-                       bh_unlock_sock(sk);
+       rcu_read_lock_bh();
+       filter = sk->sk_filter;
+       if (filter) {
+               unsigned int pkt_len = sk_run_filter(skb, filter->insns,
+                               filter->len);
+               err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
        }
+       rcu_read_unlock_bh();
+
        return err;
 }
 
@@ -897,6 +891,12 @@ static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
  *     Remove a filter from a socket and release its resources.
  */
  
+static inline void sk_filter_rcu_free(struct rcu_head *rcu)
+{
+       struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
+       kfree(fp);
+}
+
 static inline void sk_filter_release(struct sock *sk, struct sk_filter *fp)
 {
        unsigned int size = sk_filter_len(fp);
@@ -904,7 +904,7 @@ static inline void sk_filter_release(struct sock *sk, struct sk_filter *fp)
        atomic_sub(size, &sk->sk_omem_alloc);
 
        if (atomic_dec_and_test(&fp->refcnt))
-               kfree(fp);
+               call_rcu_bh(&fp->rcu, sk_filter_rcu_free);
 }
 
 static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
@@ -969,9 +969,23 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
        sk->sk_sleep = &parent->wait;
        parent->sk = sk;
        sk->sk_socket = parent;
+       security_sock_graft(sk, parent);
        write_unlock_bh(&sk->sk_callback_lock);
 }
 
+static inline void sock_copy(struct sock *nsk, const struct sock *osk)
+{
+#ifdef CONFIG_SECURITY_NETWORK
+       void *sptr = nsk->sk_security;
+#endif
+
+       memcpy(nsk, osk, osk->sk_prot->obj_size);
+#ifdef CONFIG_SECURITY_NETWORK
+       nsk->sk_security = sptr;
+       security_sk_clone(osk, nsk);
+#endif
+}
+
 extern int sock_i_uid(struct sock *sk);
 extern unsigned long sock_i_ino(struct sock *sk);