From 4581d91b7717152001192112027596fbdeec06f6 Mon Sep 17 00:00:00 2001 From: Thomas Huehn Date: Tue, 17 Jul 2012 22:16:13 +0200 Subject: mac80211_hwsim: fix possible race condition in usage of info->control.sta & control.vif info->control.sta and control.vif may only be dereferenced during the drv_tx call otherwise could lead to use-after-free bugs. Signed-off-by: Thomas Huehn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 643f968..0083839 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -739,11 +739,6 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) txi = IEEE80211_SKB_CB(skb); - if (txi->control.vif) - hwsim_check_magic(txi->control.vif); - if (txi->control.sta) - hwsim_check_sta_magic(txi->control.sta); - ieee80211_tx_info_clear_status(txi); /* frame was transmitted at most favorable rate at first attempt */ -- cgit v0.10.2 From d8f1bd2ffcce6af1ace4f1efb327765144aa0755 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 26 Jul 2012 17:44:12 +0200 Subject: bcma: fix regression in interrupt assignment on mips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wrong interrupts where assigned to the cores in bcma_core_mips_init(). This caused at least my serial console not to response to any input. This was caused by this patch which changed the order of the cores in the list: commit c334e25c9f3a95f2bd6b79fedc5170f17245b1c7 Author: Rafał Miłecki Date: Wed Jul 11 12:37:00 2012 +0200 bcma: add new cores at the end of list This should be fixed properly later so that the correct interrupt numbers are assigned to the cores independently from the ordering of the list. This patch restores the old behavior again. I will look into the problem more deeply later. I also changed the order of the list with the cores and their assigned interrupt number which gets printed to the log. Now they are printed in the same order like all the other lists of cores and like it was done before the patch which changed the order. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index b013b04..cc65b45 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -131,7 +131,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) /* backplane irq line is in use, find out who uses * it and set user to irq 0 */ - list_for_each_entry_reverse(core, &bus->cores, list) { + list_for_each_entry(core, &bus->cores, list) { if ((1 << bcma_core_mips_irqflag(core)) == oldirqflag) { bcma_core_mips_set_irq(core, 0); @@ -161,7 +161,7 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus) { struct bcma_device *core; - list_for_each_entry_reverse(core, &bus->cores, list) { + list_for_each_entry(core, &bus->cores, list) { bcma_core_mips_print_irq(core, bcma_core_mips_irq(core)); } } @@ -224,7 +224,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore) mcore->assigned_irqs = 1; /* Assign IRQs to all cores on the bus */ - list_for_each_entry_reverse(core, &bus->cores, list) { + list_for_each_entry(core, &bus->cores, list) { int mips_irq; if (core->irq) continue; -- cgit v0.10.2 From 9dbf5f55f8d35ff9aedc75267f4e4042aaf89755 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 26 Jul 2012 17:45:52 +0200 Subject: bcma: add missing iounmap on error path This should fix the problem reported by Fengguang: The coccinelle static checker emits these warnings: drivers/bcma/scan.c:466:3-9: ERROR: missing iounmap; ioremap on line 451 and execution via conditional on line 465 drivers/bcma/scan.c:540:3-9: ERROR: missing iounmap; ioremap on line 515 and execution via conditional on line 539 Reported-by: Fengguang Wu Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 5672b13..8d0b571 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -462,8 +462,10 @@ int bcma_bus_scan(struct bcma_bus *bus) while (eromptr < eromend) { struct bcma_device *other_core; struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL); - if (!core) - return -ENOMEM; + if (!core) { + err = -ENOMEM; + goto out; + } INIT_LIST_HEAD(&core->list); core->bus = bus; @@ -478,7 +480,7 @@ int bcma_bus_scan(struct bcma_bus *bus) } else if (err == -ESPIPE) { break; } - return err; + goto out; } core->core_index = core_num++; @@ -494,10 +496,12 @@ int bcma_bus_scan(struct bcma_bus *bus) list_add_tail(&core->list, &bus->cores); } + err = 0; +out: if (bus->hosttype == BCMA_HOSTTYPE_SOC) iounmap(eromptr); - return 0; + return err; } int __init bcma_bus_scan_early(struct bcma_bus *bus, @@ -537,7 +541,7 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus, else if (err == -ESPIPE) break; else if (err < 0) - return err; + goto out; core->core_index = core_num++; bus->nr_cores++; @@ -551,6 +555,7 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus, break; } +out: if (bus->hosttype == BCMA_HOSTTYPE_SOC) iounmap(eromptr); -- cgit v0.10.2 From 42493570100b91ef663c4c6f0c0fdab238f9d3c2 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 26 Jul 2012 22:52:21 +0000 Subject: tcp: Add TCP_USER_TIMEOUT negative value check TCP_USER_TIMEOUT is a TCP level socket option that takes an unsigned int. But patch "tcp: Add TCP_USER_TIMEOUT socket option"(dca43c75) didn't check the negative values. If a user assign -1 to it, the socket will set successfully and wait for 4294967295 miliseconds. This patch add a negative value check to avoid this issue. Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 581ecf0..e7e6eea 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2681,7 +2681,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, /* Cap the max timeout in ms TCP will retry/retrans * before giving up and aborting (ETIMEDOUT) a connection. */ - icsk->icsk_user_timeout = msecs_to_jiffies(val); + if (val < 0) + err = -EINVAL; + else + icsk->icsk_user_timeout = msecs_to_jiffies(val); break; default: err = -ENOPROTOOPT; -- cgit v0.10.2 From e4c7f259c5be99dcfc3d98f913590663b0305bf8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 27 Jul 2012 01:46:51 +0000 Subject: USB: kaweth.c: use GFP_ATOMIC under spin_lock The problem is that we call this with a spin lock held. The call tree is: kaweth_start_xmit() holds kaweth->device_lock. -> kaweth_async_set_rx_mode() -> kaweth_control() -> kaweth_internal_control_msg() The kaweth_internal_control_msg() function is only called from kaweth_control() which used GFP_ATOMIC for its allocations. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index d8ad552..c3d0349 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -1314,7 +1314,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, int retv; int length = 0; /* shut up GCC */ - urb = usb_alloc_urb(0, GFP_NOIO); + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM; -- cgit v0.10.2 From b1beb681cba5358f62e6187340660ade226a5fcc Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 27 Jul 2012 02:58:22 +0000 Subject: net: fix rtnetlink IFF_PROMISC and IFF_ALLMULTI handling When device flags are set using rtnetlink, IFF_PROMISC and IFF_ALLMULTI flags are handled specially. Function dev_change_flags sets IFF_PROMISC and IFF_ALLMULTI bits in dev->gflags according to the passed value but do_setlink passes a result of rtnl_dev_combine_flags which takes those bits from dev->flags. This can be easily trigerred by doing: tcpdump -i eth0 & ip l s up eth0 ip sets IFF_UP flag in ifi_flags and ifi_change, which is combined with IFF_PROMISC by rtnl_dev_combine_flags, causing __dev_change_flags to set IFF_PROMISC in gflags. Reported-by: Max Matveev Signed-off-by: Jiri Benc Signed-off-by: David S. Miller diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 334b930..bc9e380 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -659,6 +659,12 @@ static void set_operstate(struct net_device *dev, unsigned char transition) } } +static unsigned int rtnl_dev_get_flags(const struct net_device *dev) +{ + return (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI)) | + (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); +} + static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, const struct ifinfomsg *ifm) { @@ -667,7 +673,7 @@ static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ if (ifm->ifi_change) flags = (flags & ifm->ifi_change) | - (dev->flags & ~ifm->ifi_change); + (rtnl_dev_get_flags(dev) & ~ifm->ifi_change); return flags; } -- cgit v0.10.2 From 505fbcf035c245a1a42cd80184feecf61ee868dc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 27 Jul 2012 06:23:40 +0000 Subject: ipv4: fix TCP early demux commit 92101b3b2e317 (ipv4: Prepare for change of rt->rt_iif encoding.) invalidated TCP early demux, because rx_dst_ifindex is not properly initialized and checked. Also remove the use of inet_iif(skb) in favor or skb->skb_iif Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3e07a64..aa659e8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5603,6 +5603,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) if (skb != NULL) { sk->sk_rx_dst = dst_clone(skb_dst(skb)); + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; security_inet_conn_established(sk, skb); } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index b6b07c9..2fbd992 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1620,17 +1620,15 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) sock_rps_save_rxhash(sk, skb); if (sk->sk_rx_dst) { struct dst_entry *dst = sk->sk_rx_dst; - if (dst->ops->check(dst, 0) == NULL) { + if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif || + dst->ops->check(dst, 0) == NULL) { dst_release(dst); sk->sk_rx_dst = NULL; } } if (unlikely(sk->sk_rx_dst == NULL)) { - struct inet_sock *icsk = inet_sk(sk); - struct rtable *rt = skb_rtable(skb); - - sk->sk_rx_dst = dst_clone(&rt->dst); - icsk->rx_dst_ifindex = inet_iif(skb); + sk->sk_rx_dst = dst_clone(skb_dst(skb)); + inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; } if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) { rsk = sk; @@ -1709,11 +1707,11 @@ void tcp_v4_early_demux(struct sk_buff *skb) skb->destructor = sock_edemux; if (sk->sk_state != TCP_TIME_WAIT) { struct dst_entry *dst = sk->sk_rx_dst; - struct inet_sock *icsk = inet_sk(sk); + if (dst) dst = dst_check(dst, 0); if (dst && - icsk->rx_dst_ifindex == skb->skb_iif) + inet_sk(sk)->rx_dst_ifindex == skb->skb_iif) skb_dst_set_noref(skb, dst); } } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 5912ac3..3f1cc20 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -388,6 +388,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct tcp_cookie_values *oldcvp = oldtp->cookie_values; newsk->sk_rx_dst = dst_clone(skb_dst(skb)); + inet_sk(newsk)->rx_dst_ifindex = skb->skb_iif; /* TCP Cookie Transactions require space for the cookie pair, * as it differs for each connection. There is no need to -- cgit v0.10.2 From 6081030769f23c83c0564e993be146db568bf68b Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 27 Jul 2012 10:19:40 +0000 Subject: Revert "openvswitch: potential NULL deref in sample()" This reverts commit 5b3e7e6cb5771bedda51cdb6f715d1da8cd9e644. The problem that the original commit was attempting to fix can never happen in practice because validation is done one a per-flow basis rather than a per-packet basis. Adding additional checks at runtime is unnecessary and inconsistent with the rest of the code. CC: Dan Carpenter Signed-off-by: Jesse Gross Signed-off-by: David S. Miller diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 320fa0e..f3f96ba 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -325,9 +325,6 @@ static int sample(struct datapath *dp, struct sk_buff *skb, } } - if (!acts_list) - return 0; - return do_execute_actions(dp, skb, nla_data(acts_list), nla_len(acts_list), true); } -- cgit v0.10.2 From 59ea33a68a9083ac98515e4861c00e71efdc49a1 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 27 Jul 2012 10:38:50 +0000 Subject: tcp: perform DMA to userspace only if there is a task waiting for it Back in 2006, commit 1a2449a87b ("[I/OAT]: TCP recv offload to I/OAT") added support for receive offloading to IOAT dma engine if available. The code in tcp_rcv_established() tries to perform early DMA copy if applicable. It however does so without checking whether the userspace task is actually expecting the data in the buffer. This is not a problem under normal circumstances, but there is a corner case where this doesn't work -- and that's when MSG_TRUNC flag to recvmsg() is used. If the IOAT dma engine is not used, the code properly checks whether there is a valid ucopy.task and the socket is owned by userspace, but misses the check in the dmaengine case. This problem can be observed in real trivially -- for example 'tbench' is a good reproducer, as it makes a heavy use of MSG_TRUNC. On systems utilizing IOAT, you will soon find tbench waiting indefinitely in sk_wait_data(), as they have been already early-copied in tcp_rcv_established() using dma engine. This patch introduces the same check we are performing in the simple iovec copy case to the IOAT case as well. It fixes the indefinite recvmsg(MSG_TRUNC) hangs. Signed-off-by: Jiri Kosina Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index aa659e8..a356e1f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5475,7 +5475,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, if (tp->copied_seq == tp->rcv_nxt && len - tcp_header_len <= tp->ucopy.len) { #ifdef CONFIG_NET_DMA - if (tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { + if (tp->ucopy.task == current && + sock_owned_by_user(sk) && + tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { copied_early = 1; eaten = 1; } -- cgit v0.10.2