From e2e414d92397c366396d13f627a98a20be92e509 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 11:38:14 +0200 Subject: mac80211: disable mesh My kvm instance was complaining a lot about sleeping in atomic contexts in the mesh code, and it turns out that both mesh_path_add() and mpp_path_add() need to be able to sleep (they even use synchronize_rcu()!). I put in a might_sleep() to annotate that, but I see no way, at least right now, of actually making sure those functions are only called from process context since they are both called during TX and RX and the mesh code itself even calls them with rcu_read_lock() "held". Therefore, let's disable it completely for now. It's possible that I'm only seeing this because the hwsim's beaconing is broken and thus the peers aren't discovered right away, but it is possible that this happens even if beaconing is working, for a peer that doesn't exist or so. It should be possible to solve this by deferring the freeing of the tables to call_rcu() instead of using synchronize_rcu(), and also using atomic allocations, but maybe it makes more sense to rework the code to not call these from atomic contexts and defer more of the work to the workqueue. Right now, I can't work on either of those solutions though. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 1 + net/mac80211/mesh_pathtbl.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'net') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index ba2643a43c73..7836ee928983 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -83,6 +83,7 @@ endmenu config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" depends on MAC80211 && EXPERIMENTAL + depends on BROKEN ---help--- This options enables support of Draft 802.11s mesh networking. The implementation is based on Draft 1.08 of the Mesh Networking diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 3c72557df45a..02f8709a181e 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -175,6 +175,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; + might_sleep(); + if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -265,6 +267,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; + might_sleep(); if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ -- cgit v1.2.3-59-g8ed1b From f54c142725ad2ba33c3ee627873cb6966bf05447 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 21:41:39 +0200 Subject: rfkill: allow toggling soft state in sysfs again Apparently there actually _are_ tools that try to set this in sysfs even though it wasn't supposed to be used this way without claiming first. Guess what: now that I've cleaned it all up it doesn't matter and we can simply allow setting the soft-block state in sysfs. Signed-off-by: Johannes Berg Tested-By: Darren Salt Signed-off-by: John W. Linville --- net/rfkill/core.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 79693fe2001e..6896c0b45b4a 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -648,15 +648,26 @@ static ssize_t rfkill_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - /* - * The intention was that userspace can only take control over - * a given device when/if rfkill-input doesn't control it due - * to user_claim. Since user_claim is currently unsupported, - * we never support changing the state from userspace -- this - * can be implemented again later. - */ + struct rfkill *rfkill = to_rfkill(dev); + unsigned long state; + int err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + err = strict_strtoul(buf, 0, &state); + if (err) + return err; + + if (state != RFKILL_USER_STATE_SOFT_BLOCKED && + state != RFKILL_USER_STATE_UNBLOCKED) + return -EINVAL; + + mutex_lock(&rfkill_global_mutex); + rfkill_set_block(rfkill, state == RFKILL_USER_STATE_SOFT_BLOCKED); + mutex_unlock(&rfkill_global_mutex); - return -EPERM; + return err ?: count; } static ssize_t rfkill_claim_show(struct device *dev, -- cgit v1.2.3-59-g8ed1b From 8ef86c7bfac5b44529b73b84bc50d3cf574bfb4b Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 10 Jul 2009 16:42:29 -0400 Subject: mac80211: fix injection in monitor mode The location of the 802.11 header is calculated incorrectly due to a wrong placement of parentheses. Found by kmemcheck. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- net/mac80211/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d238a8939a09..3a8922cd1038 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1455,7 +1455,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) monitor_iface = UNKNOWN_ADDRESS; len_rthdr = ieee80211_get_radiotap_len(skb->data); - hdr = (struct ieee80211_hdr *)skb->data + len_rthdr; + hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); hdrlen = ieee80211_hdrlen(hdr->frame_control); /* check the header is complete in the frame */ -- cgit v1.2.3-59-g8ed1b From 48ab3578a65c5168ecaaa3b21292b643b7bcc2d5 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Sun, 12 Jul 2009 17:03:13 +0100 Subject: rfkill: fix rfkill_set_states() to set the hw state The point of this function is to set the software and hardware state at the same time. When I tried to use it, I found it was only setting the software state. Signed-off-by: Alan Jenkins Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/rfkill/core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 6896c0b45b4a..2fc4a1724eb8 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -549,6 +549,10 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) swprev = !!(rfkill->state & RFKILL_BLOCK_SW); hwprev = !!(rfkill->state & RFKILL_BLOCK_HW); __rfkill_set_sw_state(rfkill, sw); + if (hw) + rfkill->state |= RFKILL_BLOCK_HW; + else + rfkill->state &= ~RFKILL_BLOCK_HW; spin_unlock_irqrestore(&rfkill->lock, flags); -- cgit v1.2.3-59-g8ed1b From 35946a571099a50d2595c8866f07617d29558f53 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 13 Jul 2009 17:00:10 -0700 Subject: mac80211: use correct address for mesh Path Error For forwarded frames, we save the precursor address in addr1 in case it needs to be used to send a Path Error. mesh_path_discard_frame, however, was using addr2 instead of addr1 to send Path Error frames, so correct that and also make the comment regarding this more clear. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 02f8709a181e..479597e88583 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -494,8 +494,10 @@ void mesh_path_tx_pending(struct mesh_path *mpath) * @skb: frame to discard * @sdata: network subif the frame was to be sent through * - * If the frame was beign forwarded from another MP, a PERR frame will be sent - * to the precursor. + * If the frame was being forwarded from another MP, a PERR frame will be sent + * to the precursor. The precursor's address (i.e. the previous hop) was saved + * in addr1 of the frame-to-be-forwarded, and would only be overwritten once + * the destination is successfully resolved. * * Locking: the function must me called within a rcu_read_lock region */ @@ -510,7 +512,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, u8 *ra, *da; da = hdr->addr3; - ra = hdr->addr2; + ra = hdr->addr1; mpath = mesh_path_lookup(da, sdata); if (mpath) dsn = ++mpath->dsn; -- cgit v1.2.3-59-g8ed1b From 6c95e2a2f0f0bf4c8880d5b74b2f7f359d352d03 Mon Sep 17 00:00:00 2001 From: Niko Jokinen Date: Wed, 15 Jul 2009 11:00:53 +0300 Subject: nl80211: Memory leak fixed Potential memory leak via msg pointer in nl80211_get_key() function. Signed-off-by: Niko Jokinen Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 43bdb1372cae..634496b3ed77 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -997,7 +997,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(hdr)) { err = PTR_ERR(hdr); - goto out; + goto free_msg; } cookie.msg = msg; @@ -1011,7 +1011,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) &cookie, get_key_callback); if (err) - goto out; + goto free_msg; if (cookie.error) goto nla_put_failure; @@ -1022,6 +1022,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) nla_put_failure: err = -ENOBUFS; + free_msg: nlmsg_free(msg); out: cfg80211_put_dev(drv); -- cgit v1.2.3-59-g8ed1b From 9e81eccf199d910e5ea8db377a43478e4eccd033 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 19 Jul 2009 05:05:37 +0200 Subject: cfg80211: double free in __cfg80211_scan_done This patch fixes a double free corruption in __cfg80211_scan_done: ================================================ BUG kmalloc-512: Object already free ------------------------------------------------ INFO: Allocated in load_elf_binary+0x18b/0x19af age=6 INFO: Freed in load_elf_binary+0x104e/0x19af age=5 INFO: Slab 0xffffea0001bae4c0 objects=14 used=7 INFO: Object 0xffff88007e8a9918 @offset=6424 fp=0xffff88007e8a9488 Bytes b4 0xffff88007e8a9908: 00 00 00 00 00 00 00 00 5a 5a [...] Pid: 28705, comm: rmmod Tainted: P C 2.6.31-rc2-wl #1 Call Trace: [] print_trailer+0x14e/0x16e [] object_err+0x42/0x61 [] __slab_free+0x2af/0x396 [] ? wiphy_unregister+0x92/0x142 [cfg80211] [] kfree+0x13c/0x17a [] ? wiphy_unregister+0x92/0x142 [cfg80211] [] wiphy_unregister+0x92/0x142 [cfg80211] [] ieee80211_unregister_hw+0xc8/0xff [mac80211] [] p54_unregister_common+0x31/0x66 [p54common] [...] FIX kmalloc-512: Object at 0xffff88007e8a9918 not freed The code path which leads to the *funny* double free: request = rdev->scan_req; dev = dev_get_by_index(&init_net, request->ifidx); /* * the driver was unloaded recently and * therefore dev_get_by_index will return NULL! */ if (!dev) goto out; [...] rdev->scan_req = NULL; /* not executed... */ [...] out: kfree(request); Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- net/wireless/scan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/wireless/scan.c b/net/wireless/scan.c index f8e71b300001..9271118e1fc4 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -35,8 +35,6 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) else nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); - wiphy_to_dev(request->wiphy)->scan_req = NULL; - #ifdef CONFIG_WIRELESS_EXT if (!aborted) { memset(&wrqu, 0, sizeof(wrqu)); @@ -48,6 +46,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) dev_put(dev); out: + wiphy_to_dev(request->wiphy)->scan_req = NULL; kfree(request); } EXPORT_SYMBOL(cfg80211_scan_done); -- cgit v1.2.3-59-g8ed1b From dcf777f6ed9799c5ac90ac17a5c369e6b73ca92e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 26 Jul 2009 19:11:14 -0700 Subject: NET: ROSE: Don't use static buffer. The use of a static buffer in rose2asc() to return its result is not threadproof and can result in corruption if multiple threads are trying to use one of the procfs files based on rose2asc(). Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- include/net/rose.h | 2 +- net/rose/af_rose.c | 18 ++++++++---------- net/rose/rose_route.c | 23 ++++++++++++----------- 3 files changed, 21 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/include/net/rose.h b/include/net/rose.h index cbd5364b2c8a..5ba9f02731eb 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -156,7 +156,7 @@ extern int sysctl_rose_maximum_vcs; extern int sysctl_rose_window_size; extern int rosecmp(rose_address *, rose_address *); extern int rosecmpm(rose_address *, rose_address *, unsigned short); -extern const char *rose2asc(const rose_address *); +extern char *rose2asc(char *buf, const rose_address *); extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *); extern void rose_kill_by_neigh(struct rose_neigh *); extern unsigned int rose_new_lci(struct rose_neigh *); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 6bd8e93869ed..f0a76f6bca71 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -92,23 +92,21 @@ static void rose_set_lockdep_key(struct net_device *dev) /* * Convert a ROSE address into text. */ -const char *rose2asc(const rose_address *addr) +char *rose2asc(char *buf, const rose_address *addr) { - static char buffer[11]; - if (addr->rose_addr[0] == 0x00 && addr->rose_addr[1] == 0x00 && addr->rose_addr[2] == 0x00 && addr->rose_addr[3] == 0x00 && addr->rose_addr[4] == 0x00) { - strcpy(buffer, "*"); + strcpy(buf, "*"); } else { - sprintf(buffer, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF, + sprintf(buf, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF, addr->rose_addr[1] & 0xFF, addr->rose_addr[2] & 0xFF, addr->rose_addr[3] & 0xFF, addr->rose_addr[4] & 0xFF); } - return buffer; + return buf; } /* @@ -1437,7 +1435,7 @@ static void rose_info_stop(struct seq_file *seq, void *v) static int rose_info_show(struct seq_file *seq, void *v) { - char buf[11]; + char buf[11], rsbuf[11]; if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -1455,8 +1453,8 @@ static int rose_info_show(struct seq_file *seq, void *v) devname = dev->name; seq_printf(seq, "%-10s %-9s ", - rose2asc(&rose->dest_addr), - ax2asc(buf, &rose->dest_call)); + rose2asc(rsbuf, &rose->dest_addr), + ax2asc(buf, &rose->dest_call)); if (ax25cmp(&rose->source_call, &null_ax25_address) == 0) callsign = "??????-?"; @@ -1465,7 +1463,7 @@ static int rose_info_show(struct seq_file *seq, void *v) seq_printf(seq, "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n", - rose2asc(&rose->source_addr), + rose2asc(rsbuf, &rose->source_addr), callsign, devname, rose->lci & 0x0FFF, diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index a81066a1010a..9478d9b3d977 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -1104,6 +1104,7 @@ static void rose_node_stop(struct seq_file *seq, void *v) static int rose_node_show(struct seq_file *seq, void *v) { + char rsbuf[11]; int i; if (v == SEQ_START_TOKEN) @@ -1112,13 +1113,13 @@ static int rose_node_show(struct seq_file *seq, void *v) const struct rose_node *rose_node = v; /* if (rose_node->loopback) { seq_printf(seq, "%-10s %04d 1 loopback\n", - rose2asc(&rose_node->address), - rose_node->mask); + rose2asc(rsbuf, &rose_node->address), + rose_node->mask); } else { */ seq_printf(seq, "%-10s %04d %d", - rose2asc(&rose_node->address), - rose_node->mask, - rose_node->count); + rose2asc(rsbuf, &rose_node->address), + rose_node->mask, + rose_node->count); for (i = 0; i < rose_node->count; i++) seq_printf(seq, " %05d", @@ -1267,7 +1268,7 @@ static void rose_route_stop(struct seq_file *seq, void *v) static int rose_route_show(struct seq_file *seq, void *v) { - char buf[11]; + char buf[11], rsbuf[11]; if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -1279,7 +1280,7 @@ static int rose_route_show(struct seq_file *seq, void *v) seq_printf(seq, "%3.3X %-10s %-9s %05d ", rose_route->lci1, - rose2asc(&rose_route->src_addr), + rose2asc(rsbuf, &rose_route->src_addr), ax2asc(buf, &rose_route->src_call), rose_route->neigh1->number); else @@ -1289,10 +1290,10 @@ static int rose_route_show(struct seq_file *seq, void *v) if (rose_route->neigh2) seq_printf(seq, "%3.3X %-10s %-9s %05d\n", - rose_route->lci2, - rose2asc(&rose_route->dest_addr), - ax2asc(buf, &rose_route->dest_call), - rose_route->neigh2->number); + rose_route->lci2, + rose2asc(rsbuf, &rose_route->dest_addr), + ax2asc(buf, &rose_route->dest_call), + rose_route->neigh2->number); else seq_puts(seq, "000 * * 00000\n"); -- cgit v1.2.3-59-g8ed1b From c587aea951a56d29741a3cef4ea3e142c93b3207 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Thu, 23 Jul 2009 23:06:32 +0000 Subject: net/bridge: use kobject_put to release kobject in br_add_if error path kobject_init_and_add will alloc memory for kobj->name, so in br_add_if error path, simply use kobject_del will not free memory for kobj->name. Fix by using kobject_put instead, kobject_put will internally calls kobject_del and frees memory for kobj->name. Signed-off-by: Xiaotian Feng Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 8a96672e2c5c..eb404dc3ed6e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -424,7 +424,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) err2: br_fdb_delete_by_port(br, p, 1); err1: - kobject_del(&p->kobj); + kobject_put(&p->kobj); err0: dev_set_promiscuity(dev, -1); put_back: -- cgit v1.2.3-59-g8ed1b From 0cbb0a781a42f131e9c6836554f402cb85f8f38b Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Mon, 27 Jul 2009 10:49:44 -0700 Subject: net: irda: init spinlock after memcpy irttp_dup() copies a tsap_cb struct, but does not initialize the spinlock in the new structure, which confuses lockdep. Signed-off-by: Deepak Saxena Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: David S. Miller --- net/irda/irttp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/irda/irttp.c b/net/irda/irttp.c index ecf4eb2717cb..9cb79f95bf63 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -1453,6 +1453,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) } /* Dup */ memcpy(new, orig, sizeof(struct tsap_cb)); + spin_lock_init(&new->lock); /* We don't need the old instance any more */ spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); -- cgit v1.2.3-59-g8ed1b