tcp: sysctl interface leaks 16 bytes of kernel memory
[platform/adaptation/renesas_rcar/renesas_kernel.git] / net / netlink / af_netlink.c
index 0f2e3ad..01e944a 100644 (file)
@@ -169,6 +169,8 @@ static void netlink_sock_destruct(struct sock *sk)
        if (nlk->cb) {
                if (nlk->cb->done)
                        nlk->cb->done(nlk->cb);
+
+               module_put(nlk->cb->module);
                netlink_destroy_callback(nlk->cb);
        }
 
@@ -1758,6 +1760,7 @@ static int netlink_dump(struct sock *sk)
        nlk->cb = NULL;
        mutex_unlock(nlk->cb_mutex);
 
+       module_put(cb->module);
        netlink_consume_callback(cb);
        return 0;
 
@@ -1767,9 +1770,9 @@ errout_skb:
        return err;
 }
 
-int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
-                      const struct nlmsghdr *nlh,
-                      struct netlink_dump_control *control)
+int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+                        const struct nlmsghdr *nlh,
+                        struct netlink_dump_control *control)
 {
        struct netlink_callback *cb;
        struct sock *sk;
@@ -1784,6 +1787,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        cb->done = control->done;
        cb->nlh = nlh;
        cb->data = control->data;
+       cb->module = control->module;
        cb->min_dump_alloc = control->min_dump_alloc;
        atomic_inc(&skb->users);
        cb->skb = skb;
@@ -1794,19 +1798,28 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
                return -ECONNREFUSED;
        }
        nlk = nlk_sk(sk);
-       /* A dump is in progress... */
+
        mutex_lock(nlk->cb_mutex);
+       /* A dump is in progress... */
        if (nlk->cb) {
                mutex_unlock(nlk->cb_mutex);
                netlink_destroy_callback(cb);
-               sock_put(sk);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out;
        }
+       /* add reference of module which cb->dump belongs to */
+       if (!try_module_get(cb->module)) {
+               mutex_unlock(nlk->cb_mutex);
+               netlink_destroy_callback(cb);
+               ret = -EPROTONOSUPPORT;
+               goto out;
+       }
+
        nlk->cb = cb;
        mutex_unlock(nlk->cb_mutex);
 
        ret = netlink_dump(sk);
-
+out:
        sock_put(sk);
 
        if (ret)
@@ -1817,7 +1830,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
         */
        return -EINTR;
 }
-EXPORT_SYMBOL(netlink_dump_start);
+EXPORT_SYMBOL(__netlink_dump_start);
 
 void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
 {