Subject: [PATCH] netlink: Use the appropriate reply socket! From: Eric W. Biederman Date: 1133703909 -0700 - Remove the socket parameter from netlink_dump_start we already have that information in the skb parameter and no one was passing skb->sk like they should have - In nfnl_callback the call member took a sock and also took a skb And of course the too values were not forced to match so remove the useless socket parameter. - Updated all of the users of struct nfnl_callback and netlink_dump_start - Add nethost reference counting in the netlink sockets. - Add netlink_host_broadcast. It is just like netlink_broadcast except it will only broadcast to sockets for a single host. --- include/linux/netfilter/nfnetlink.h | 2 +- include/linux/netlink.h | 5 ++++- net/core/rtnetlink.c | 2 +- net/ipv4/inet_diag.c | 2 +- net/ipv4/netfilter/ip_conntrack_netlink.c | 22 +++++++++++----------- net/netfilter/nfnetlink.c | 4 ++-- net/netfilter/nfnetlink_log.c | 4 ++-- net/netfilter/nfnetlink_queue.c | 6 +++--- net/netlink/af_netlink.c | 26 ++++++++++++++++++++------ net/xfrm/xfrm_user.c | 8 ++++---- 10 files changed, 49 insertions(+), 32 deletions(-) 45a00aa0b2f1e19c441207ea39e3081bd1b29c5a diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 1d5b10a..39a85b5 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -106,7 +106,7 @@ struct nfgenmsg { struct nfnl_callback { - int (*call)(struct sock *nl, struct sk_buff *skb, + int (*call)(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp); kernel_cap_t cap_required; /* capabilities required for this msg */ u_int16_t attr_count; /* number of nfattr's */ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 9a3d6bd..a0812dd 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -132,6 +132,9 @@ extern void netlink_ack(struct sk_buff * extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, __u32 group, gfp_t allocation); +extern int netlink_host_broadcast(struct sock *ssk, struct sk_buff *skb, + struct nethost *host, __u32 pid, + __u32 group, gfp_t allocation); extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); extern int netlink_register_notifier(struct notifier_block *nb); extern int netlink_unregister_notifier(struct notifier_block *nb); @@ -201,7 +204,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid ({ skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \ -1; }) -extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, +extern int netlink_dump_start(struct sk_buff *skb, struct nlmsghdr *nlh, int (*dump)(struct sk_buff *skb, struct netlink_callback*), int (*done)(struct netlink_callback*)); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 0e2f0c5..d772360 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -532,7 +532,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, s if (link->dumpit == NULL) goto err_inval; - if ((*errp = netlink_dump_start(rtnl, skb, nlh, + if ((*errp = netlink_dump_start(skb, nlh, link->dumpit, rtnetlink_done)) != 0) { return -1; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 71f3c73..da8cc37 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -759,7 +759,7 @@ inet_diag_rcv_msg(struct sk_buff *skb, s if (inet_diag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta))) goto err_inval; } - return netlink_dump_start(idiagnl, skb, nlh, + return netlink_dump_start(skb, nlh, inet_diag_dump, inet_diag_dump_done); } else { diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index b08a432..539150f 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -693,7 +693,7 @@ nfattr_failure: } static int -ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, +ctnetlink_del_conntrack(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) { struct ip_conntrack_tuple_hash *h; @@ -743,7 +743,7 @@ ctnetlink_del_conntrack(struct sock *ctn } static int -ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, +ctnetlink_get_conntrack(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) { struct ip_conntrack_tuple_hash *h; @@ -764,7 +764,7 @@ ctnetlink_get_conntrack(struct sock *ctn if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) { #ifdef CONFIG_IP_NF_CT_ACCT - if ((*errp = netlink_dump_start(ctnl, skb, nlh, + if ((*errp = netlink_dump_start(skb, nlh, ctnetlink_dump_table_w, ctnetlink_done)) != 0) return -EINVAL; @@ -772,7 +772,7 @@ ctnetlink_get_conntrack(struct sock *ctn return -ENOTSUPP; #endif } else { - if ((*errp = netlink_dump_start(ctnl, skb, nlh, + if ((*errp = netlink_dump_start(skb, nlh, ctnetlink_dump_table, ctnetlink_done)) != 0) return -EINVAL; @@ -817,7 +817,7 @@ ctnetlink_get_conntrack(struct sock *ctn if (err <= 0) goto out; - err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); + err = netlink_unicast(skb->sk, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); if (err < 0) goto out; @@ -1019,7 +1019,7 @@ err: } static int -ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, +ctnetlink_new_conntrack(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) { struct ip_conntrack_tuple otuple, rtuple; @@ -1234,7 +1234,7 @@ out: } static int -ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, +ctnetlink_get_expect(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) { struct ip_conntrack_tuple tuple; @@ -1251,7 +1251,7 @@ ctnetlink_get_expect(struct sock *ctnl, if (msg->nfgen_family != AF_INET) return -EAFNOSUPPORT; - if ((*errp = netlink_dump_start(ctnl, skb, nlh, + if ((*errp = netlink_dump_start(skb, nlh, ctnetlink_exp_dump_table, ctnetlink_done)) != 0) return -EINVAL; @@ -1288,7 +1288,7 @@ ctnetlink_get_expect(struct sock *ctnl, ip_conntrack_expect_put(exp); - err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); + err = netlink_unicast(skb->sk, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); if (err < 0) goto free; @@ -1303,7 +1303,7 @@ free: } static int -ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, +ctnetlink_del_expect(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) { struct ip_conntrack_expect *exp, *tmp; @@ -1431,7 +1431,7 @@ out: } static int -ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, +ctnetlink_new_expect(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) { struct ip_conntrack_tuple tuple; diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 1caaca0..2cf64af 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -278,7 +278,7 @@ static inline int nfnetlink_rcv_msg(stru goto err_inval; DEBUGP("calling handler\n"); - err = nc->call(nfnl, skb, nlh, cda, errp); + err = nc->call(skb, nlh, cda, errp); *errp = err; return err; } @@ -341,7 +341,7 @@ static void nfnetlink_rcv(struct sock *s /* don't call nfnl_shunlock, since it would reenter * with further packet processing */ up(&nfnl_sem); - } while(nfnl && nfnl->sk_receive_queue.qlen); + } while(sk->sk_receive_queue.qlen); } static void __exit nfnetlink_exit(void) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index efcd10f..1d4f0c2 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -715,7 +715,7 @@ static struct notifier_block nfulnl_rtnl }; static int -nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, +nfulnl_recv_unsupp(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) { return -ENOTSUPP; @@ -748,7 +748,7 @@ static const int nfula_cfg_min[NFULA_CFG }; static int -nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, +nfulnl_recv_config(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *nfula[], int *errp) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index eaa44c4..5fa4f04 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -765,7 +765,7 @@ static const int nfqa_verdict_min[NFQA_M }; static int -nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, +nfqnl_recv_verdict(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); @@ -829,7 +829,7 @@ err_out_put: } static int -nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, +nfqnl_recv_unsupp(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) { return -ENOTSUPP; @@ -846,7 +846,7 @@ static struct nf_queue_handler nfqh = { }; static int -nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, +nfqnl_recv_config(struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index fb5a223..59219f6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -421,6 +421,7 @@ static int netlink_create(struct socket goto out_module; sock->sk->sk_host = current->host; + get_host(sock->sk->sk_host); nlk = nlk_sk(sock->sk); nlk->module = module; out: @@ -449,6 +450,10 @@ static int netlink_release(struct socket nlk->cb = NULL; } spin_unlock(&nlk->cb_lock); + if (sk->sk_host) { + put_host(sk->sk_host); + sk->sk_host = NULL; + } /* OK. Socket is unlinked, and, therefore, no new packets will arrive */ @@ -901,8 +906,9 @@ out: return 0; } -int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, - u32 group, gfp_t allocation) +int netlink_host_broadcast(struct sock *ssk, struct sk_buff *skb, + struct nethost *host, u32 pid, + u32 group, gfp_t allocation) { struct netlink_broadcast_data info; struct hlist_node *node; @@ -911,7 +917,7 @@ int netlink_broadcast(struct sock *ssk, skb = netlink_trim(skb, allocation); info.exclude_sk = ssk; - info.host = ssk->sk_host; + info.host = host; info.pid = pid; info.group = group; info.failure = 0; @@ -945,6 +951,13 @@ int netlink_broadcast(struct sock *ssk, return -ESRCH; } +int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, + u32 group, gfp_t allocation) +{ + return netlink_host_broadcast(ssk, skb, ssk->sk_host, pid, group, + allocation); +} + struct netlink_set_err_data { struct sock *exclude_sk; u32 pid; @@ -1366,7 +1379,7 @@ nlmsg_failure: return -ENOBUFS; } -int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, +int netlink_dump_start(struct sk_buff *skb, struct nlmsghdr *nlh, int (*dump)(struct sk_buff *skb, struct netlink_callback*), int (*done)(struct netlink_callback*)) @@ -1386,7 +1399,8 @@ int netlink_dump_start(struct sock *ssk, atomic_inc(&skb->users); cb->skb = skb; - sk = netlink_lookup(skb->sk->sk_host, ssk->sk_protocol, NETLINK_CB(skb).pid); + sk = netlink_lookup(skb->sk->sk_host, skb->sk->sk_protocol, + NETLINK_CB(skb).pid); if (sk == NULL) { netlink_destroy_callback(cb); return -ECONNREFUSED; @@ -1622,7 +1636,7 @@ static struct proto_ops netlink_ops = { static struct net_proto_family netlink_family_ops = { .family = PF_NETLINK, .create = netlink_create, - .multi_host = 1, /* FIXME this is currently A lie... */ + .multi_host = 1, .owner = THIS_MODULE, /* for consistency 8) */ }; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c35336a..cb41473 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -458,7 +458,7 @@ static int xfrm_get_sa(struct sk_buff *s if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = netlink_unicast(xfrm_nl, resp_skb, + err = netlink_unicast(skb->sk, resp_skb, NETLINK_CB(skb).pid, MSG_DONTWAIT); } xfrm_state_put(x); @@ -539,7 +539,7 @@ static int xfrm_alloc_userspi(struct sk_ goto out; } - err = netlink_unicast(xfrm_nl, resp_skb, + err = netlink_unicast(skb->sk, resp_skb, NETLINK_CB(skb).pid, MSG_DONTWAIT); out: @@ -864,7 +864,7 @@ static int xfrm_get_policy(struct sk_buf if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = netlink_unicast(xfrm_nl, resp_skb, + err = netlink_unicast(skb->sk, resp_skb, NETLINK_CB(skb).pid, MSG_DONTWAIT); } @@ -989,7 +989,7 @@ static int xfrm_user_rcv_msg(struct sk_b if (link->dump == NULL) goto err_einval; - if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, + if ((*errp = netlink_dump_start(skb, nlh, link->dump, xfrm_done)) != 0) { return -1; -- 1.0.GIT