From 68d6ac6d2740b6a55f3ae92a4e0be6d881904b32 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 15 Aug 2010 21:20:44 +0000 Subject: netlink: fix compat recvmsg Since commit 1dacc76d0014a034b8aca14237c127d7c19d7726 Author: Johannes Berg Date: Wed Jul 1 11:26:02 2009 +0000 net/compat/wext: send different messages to compat tasks we had a race condition when setting and then restoring frag_list. Eric attempted to fix it, but the fix created even worse problems. However, the original motivation I had when I added the code that turned out to be racy is no longer clear to me, since we only copy up to skb->len to userspace, which doesn't include the frag_list length. As a result, not doing any frag_list clearing and restoring avoids the race condition, while not introducing any other problems. Additionally, while preparing this patch I found that since none of the remaining netlink code is really aware of the frag_list, we need to use the original skb's information for packet information and credentials. This fixes, for example, the group information received by compat tasks. Cc: Eric Dumazet Cc: stable@kernel.org [2.6.31+, for 2.6.35 revert 1235f504aa] Signed-off-by: Johannes Berg Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8648a9922aab..980fe4ad0016 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1406,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, struct netlink_sock *nlk = nlk_sk(sk); int noblock = flags&MSG_DONTWAIT; size_t copied; - struct sk_buff *skb, *frag __maybe_unused = NULL; + struct sk_buff *skb, *data_skb; int err; if (flags&MSG_OOB) @@ -1418,45 +1418,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, if (skb == NULL) goto out; + data_skb = skb; + #ifdef CONFIG_COMPAT_NETLINK_MESSAGES if (unlikely(skb_shinfo(skb)->frag_list)) { - bool need_compat = !!(flags & MSG_CMSG_COMPAT); - /* - * If this skb has a frag_list, then here that means that - * we will have to use the frag_list skb for compat tasks - * and the regular skb for non-compat tasks. + * If this skb has a frag_list, then here that means that we + * will have to use the frag_list skb's data for compat tasks + * and the regular skb's data for normal (non-compat) tasks. * - * The skb might (and likely will) be cloned, so we can't - * just reset frag_list and go on with things -- we need to - * keep that. For the compat case that's easy -- simply get - * a reference to the compat skb and free the regular one - * including the frag. For the non-compat case, we need to - * avoid sending the frag to the user -- so assign NULL but - * restore it below before freeing the skb. + * If we need to send the compat skb, assign it to the + * 'data_skb' variable so that it will be used below for data + * copying. We keep 'skb' for everything else, including + * freeing both later. */ - if (need_compat) { - struct sk_buff *compskb = skb_shinfo(skb)->frag_list; - skb_get(compskb); - kfree_skb(skb); - skb = compskb; - } else { - frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; - } + if (flags & MSG_CMSG_COMPAT) + data_skb = skb_shinfo(skb)->frag_list; } #endif msg->msg_namelen = 0; - copied = skb->len; + copied = data_skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; copied = len; } - skb_reset_transport_header(skb); - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + skb_reset_transport_header(data_skb); + err = skb_copy_datagram_iovec(data_skb, 0, msg->msg_iov, copied); if (msg->msg_name) { struct sockaddr_nl *addr = (struct sockaddr_nl *)msg->msg_name; @@ -1476,11 +1466,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, } siocb->scm->creds = *NETLINK_CREDS(skb); if (flags & MSG_TRUNC) - copied = skb->len; - -#ifdef CONFIG_COMPAT_NETLINK_MESSAGES - skb_shinfo(skb)->frag_list = frag; -#endif + copied = data_skb->len; skb_free_datagram(sk, skb); -- cgit v1.2.3 From f037590fff3005ce8a1513858d7d44f50053cc8f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Aug 2010 03:25:00 +0000 Subject: rds: fix a leak of kernel memory struct rds_rdma_notify contains a 32 bits hole on 64bit arches, make sure it is zeroed before copying it to user. Signed-off-by: Eric Dumazet CC: Andy Grover Signed-off-by: David S. Miller --- net/rds/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/rds/recv.c b/net/rds/recv.c index 795a00b7f2cb..c93588c2d553 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -297,7 +297,7 @@ static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc, int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msghdr) { struct rds_notifier *notifier; - struct rds_rdma_notify cmsg; + struct rds_rdma_notify cmsg = { 0 }; /* fill holes with zero */ unsigned int count = 0, max_messages = ~0U; unsigned long flags; LIST_HEAD(copy); -- cgit v1.2.3 From 0ac820eebe9008094040955d294ef7b33b418413 Mon Sep 17 00:00:00 2001 From: Phil Oester Date: Tue, 17 Aug 2010 18:45:08 +0000 Subject: vlan: Match underlying dev carrier on vlan add When adding a new vlan, if the underlying interface has no carrier, then the newly added vlan interface should also have no carrier. At present, this is not true - the newly added vlan is added with carrier up. Fix by checking state of real device. Signed-off-by: Phil Oester Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 3d59c9bf8feb..3bccdd12a264 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -510,7 +510,8 @@ static int vlan_dev_open(struct net_device *dev) if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); - netif_carrier_on(dev); + if (netif_carrier_ok(real_dev)) + netif_carrier_on(dev); return 0; clear_allmulti: -- cgit v1.2.3 From 79c5f51c639021f7472591239c3867cee4b9ec02 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Aug 2010 00:24:43 +0000 Subject: irda: fix a race in irlan_eth_xmit() After skb is queued, its illegal to dereference it. Cache skb->len into a temporary variable. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/irda/irlan/irlan_eth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 9616c32d1076..5bb8353105cc 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -169,6 +169,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, { struct irlan_cb *self = netdev_priv(dev); int ret; + unsigned int len; /* skb headroom large enough to contain all IrDA-headers? */ if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) { @@ -188,6 +189,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, dev->trans_start = jiffies; + len = skb->len; /* Now queue the packet in the transport layer */ if (self->use_udata) ret = irttp_udata_request(self->tsap_data, skb); @@ -209,7 +211,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, self->stats.tx_dropped++; } else { self->stats.tx_packets++; - self->stats.tx_bytes += skb->len; + self->stats.tx_bytes += len; } return NETDEV_TX_OK; -- cgit v1.2.3 From cca77b7c81876d819a5806f408b3c29b5b61a815 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 23 Aug 2010 14:41:22 -0700 Subject: netfilter: fix CONFIG_COMPAT support commit f3c5c1bfd430858d3a05436f82c51e53104feb6b (netfilter: xtables: make ip_tables reentrant) forgot to also compute the jumpstack size in the compat handlers. Result is that "iptables -I INPUT -j userchain" turns into -j DROP. Reported by Sebastian Roesner on #netfilter, closes http://bugzilla.netfilter.org/show_bug.cgi?id=669. Note: arptables change is compile-tested only. Signed-off-by: Florian Westphal Acked-by: Eric Dumazet Tested-by: Mikael Pettersson Signed-off-by: David S. Miller --- net/ipv4/netfilter/arp_tables.c | 3 +++ net/ipv4/netfilter/ip_tables.c | 3 +++ net/ipv6/netfilter/ip6_tables.c | 3 +++ 3 files changed, 9 insertions(+) (limited to 'net') diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 51d6c3167975..e8f4f9a57f12 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1420,6 +1420,9 @@ static int translate_compat_table(const char *name, if (ret != 0) break; ++i; + if (strcmp(arpt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 97b64b22c412..d163f2e3b2e9 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1751,6 +1751,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ipt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 29a7bca29e3f..8e754be92c24 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1766,6 +1766,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ip6t_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* -- cgit v1.2.3