From 995c99268e0b12eb3c8939211ba5368dd92d98d9 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 30 Apr 2006 19:49:30 +0100 Subject: [PATCH] softmac: don't reassociate if user asked for deauthentication When wpa_supplicant exits, it uses SIOCSIWMLME to request deauthentication. softmac then tries to reassociate without any user intervention, which isn't the desired behaviour of this signal. This change makes softmac only attempt reassociation if the remote network itself deauthenticated us. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/ieee80211/softmac/ieee80211softmac_auth.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 9a0eac6c61eb..d6a04f3ab86c 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -298,8 +298,6 @@ ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac, /* can't transmit data right now... */ netif_carrier_off(mac->dev); - /* let's try to re-associate */ - schedule_work(&mac->associnfo.work); spin_unlock_irqrestore(&mac->lock, flags); } @@ -360,5 +358,8 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de } ieee80211softmac_deauth_from_net(mac, net); + + /* let's try to re-associate */ + schedule_work(&mac->associnfo.work); return 0; } -- cgit v1.2.2 From d57336e3f2dd7c2d1fbe4a8323029869fb6e1f00 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 30 Apr 2006 22:09:07 +0100 Subject: [PATCH] softmac: make non-operational after being stopped zd1211 with softmac and wpa_supplicant revealed an issue with softmac and the use of workqueues. Some of the work functions actually reschedule themselves, so this meant that there could still be pending work after flush_scheduled_work() had been called during ieee80211softmac_stop(). This patch introduces a "running" flag which is used to ensure that rescheduling does not happen in this situation. I also used this flag to ensure that softmac's hooks into ieee80211 are non-operational once the stop operation has been started. This simply makes softmac a little more robust, because I could crash it easily by receiving frames in the short timeframe after shutting down softmac and before turning off the ZD1211 radio. (ZD1211 is now fixed as well!) Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/ieee80211/softmac/ieee80211softmac_assoc.c | 17 +++++++++++++++-- net/ieee80211/softmac/ieee80211softmac_auth.c | 11 +++++++++++ net/ieee80211/softmac/ieee80211softmac_module.c | 4 ++++ net/ieee80211/softmac/ieee80211softmac_scan.c | 8 ++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index fb79ce7d6439..57ea9f6f465c 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -51,11 +51,12 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft spin_lock_irqsave(&mac->lock, flags); mac->associnfo.associating = 1; mac->associated = 0; /* just to make sure */ - spin_unlock_irqrestore(&mac->lock, flags); /* Set a timer for timeout */ /* FIXME: make timeout configurable */ - schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ); + if (likely(mac->running)) + schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ); + spin_unlock_irqrestore(&mac->lock, flags); } void @@ -319,6 +320,9 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, u16 status = le16_to_cpup(&resp->status); struct ieee80211softmac_network *network = NULL; unsigned long flags; + + if (unlikely(!mac->running)) + return -ENODEV; spin_lock_irqsave(&mac->lock, flags); @@ -377,10 +381,16 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, { struct ieee80211softmac_device *mac = ieee80211_priv(dev); unsigned long flags; + + if (unlikely(!mac->running)) + return -ENODEV; + if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN)) return 0; + if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN)) return 0; + dprintk(KERN_INFO PFX "got disassoc frame\n"); netif_carrier_off(dev); spin_lock_irqsave(&mac->lock, flags); @@ -400,6 +410,9 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, struct ieee80211softmac_device *mac = ieee80211_priv(dev); struct ieee80211softmac_network *network; + if (unlikely(!mac->running)) + return -ENODEV; + network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3); if (!network) { dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index d6a04f3ab86c..06e332624665 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -86,6 +86,11 @@ ieee80211softmac_auth_queue(void *data) /* Lock and set flags */ spin_lock_irqsave(&mac->lock, flags); + if (unlikely(!mac->running)) { + /* Prevent reschedule on workqueue flush */ + spin_unlock_irqrestore(&mac->lock, flags); + return; + } net->authenticated = 0; net->authenticating = 1; /* add a timeout call so we eventually give up waiting for an auth reply */ @@ -124,6 +129,9 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) unsigned long flags; u8 * data; + if (unlikely(!mac->running)) + return -ENODEV; + /* Find correct auth queue item */ spin_lock_irqsave(&mac->lock, flags); list_for_each(list_ptr, &mac->auth_queue) { @@ -336,6 +344,9 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de struct ieee80211softmac_network *net = NULL; struct ieee80211softmac_device *mac = ieee80211_priv(dev); + if (unlikely(!mac->running)) + return -ENODEV; + if (!deauth) { dprintk("deauth without deauth packet. eek!\n"); return 0; diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c index be83bdc1644a..6252be2c0db9 100644 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ b/net/ieee80211/softmac/ieee80211softmac_module.c @@ -89,6 +89,8 @@ ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm) ieee80211softmac_wait_for_scan(sm); spin_lock_irqsave(&sm->lock, flags); + sm->running = 0; + /* Free all pending assoc work items */ cancel_delayed_work(&sm->associnfo.work); @@ -204,6 +206,8 @@ void ieee80211softmac_start(struct net_device *dev) assert(0); if (mac->txrates_change) mac->txrates_change(dev, change, &oldrates); + + mac->running = 1; } EXPORT_SYMBOL_GPL(ieee80211softmac_start); diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c index 2b9e7edfa3ce..d31cf77498c4 100644 --- a/net/ieee80211/softmac/ieee80211softmac_scan.c +++ b/net/ieee80211/softmac/ieee80211softmac_scan.c @@ -115,7 +115,15 @@ void ieee80211softmac_scan(void *d) // TODO: is this if correct, or should we do this only if scanning from assoc request? if (sm->associnfo.req_essid.len) ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0); + + spin_lock_irqsave(&sm->lock, flags); + if (unlikely(!sm->running)) { + /* Prevent reschedule on workqueue flush */ + spin_unlock_irqrestore(&sm->lock, flags); + break; + } schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY); + spin_unlock_irqrestore(&sm->lock, flags); return; } else { dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel); -- cgit v1.2.2 From fe9925b551a95fae6ec61470c79f8b701a2fe928 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 6 May 2006 17:56:03 -0700 Subject: [NET]: Create netdev attribute_groups with class_device_add Atomically create attributes when class device is added. This avoids the race between registering class_device (which generates hotplug event), and the creation of attribute groups. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- net/core/net-sysfs.c | 49 ++++++++++++------------------------------------- 2 files changed, 13 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 3bad1afc89fa..9ab3cfa58466 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3043,11 +3043,11 @@ void netdev_run_todo(void) switch(dev->reg_state) { case NETREG_REGISTERING: - dev->reg_state = NETREG_REGISTERED; err = netdev_register_sysfs(dev); if (err) printk(KERN_ERR "%s: failed sysfs registration (%d)\n", dev->name, err); + dev->reg_state = NETREG_REGISTERED; break; case NETREG_UNREGISTERING: diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index c12990c9c603..47a6fceb6771 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -29,7 +29,7 @@ static const char fmt_ulong[] = "%lu\n"; static inline int dev_isalive(const struct net_device *dev) { - return dev->reg_state == NETREG_REGISTERED; + return dev->reg_state <= NETREG_REGISTERED; } /* use same locking rules as GIF* ioctl's */ @@ -445,58 +445,33 @@ static struct class net_class = { void netdev_unregister_sysfs(struct net_device * net) { - struct class_device * class_dev = &(net->class_dev); - - if (net->get_stats) - sysfs_remove_group(&class_dev->kobj, &netstat_group); - -#ifdef WIRELESS_EXT - if (net->get_wireless_stats || (net->wireless_handlers && - net->wireless_handlers->get_wireless_stats)) - sysfs_remove_group(&class_dev->kobj, &wireless_group); -#endif - class_device_del(class_dev); - + class_device_del(&(net->class_dev)); } /* Create sysfs entries for network device. */ int netdev_register_sysfs(struct net_device *net) { struct class_device *class_dev = &(net->class_dev); - int ret; + struct attribute_group **groups = net->sysfs_groups; + class_device_initialize(class_dev); class_dev->class = &net_class; class_dev->class_data = net; + class_dev->groups = groups; + BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE); - if ((ret = class_device_register(class_dev))) - goto out; - if (net->get_stats && - (ret = sysfs_create_group(&class_dev->kobj, &netstat_group))) - goto out_unreg; + if (net->get_stats) + *groups++ = &netstat_group; #ifdef WIRELESS_EXT - if (net->get_wireless_stats || (net->wireless_handlers && - net->wireless_handlers->get_wireless_stats)) { - ret = sysfs_create_group(&class_dev->kobj, &wireless_group); - if (ret) - goto out_cleanup; - } - return 0; -out_cleanup: - if (net->get_stats) - sysfs_remove_group(&class_dev->kobj, &netstat_group); -#else - return 0; + if (net->get_wireless_stats + || (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)) + *groups++ = &wireless_group; #endif -out_unreg: - printk(KERN_WARNING "%s: sysfs attribute registration failed %d\n", - net->name, ret); - class_device_unregister(class_dev); -out: - return ret; + return class_device_add(class_dev); } int netdev_sysfs_init(void) -- cgit v1.2.2 From 0182bd2b1e2fb45a55f110795bfdb9aa5f6c6b0b Mon Sep 17 00:00:00 2001 From: Hua Zhong Date: Sat, 6 May 2006 18:11:39 -0700 Subject: [IPV4]: Remove likely in ip_rcv_finish() This is another result from my likely profiling tool (dwalker@mvista.com just sent the patch of the profiling tool to linux-kernel mailing list, which is similar to what I use). On my system (not very busy, normal development machine within a VMWare workstation), I see a 6/5 miss/hit ratio for this "likely". Signed-off-by: Hua Zhong Signed-off-by: David S. Miller --- net/ipv4/ip_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 18d7fad474d7..c9026dbf4c93 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -337,7 +337,7 @@ static inline int ip_rcv_finish(struct sk_buff *skb) * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ - if (likely(skb->dst == NULL)) { + if (skb->dst == NULL) { int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { -- cgit v1.2.2 From 63cbd2fda38f3d1f107c4fd6261e5660be3eccf9 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 May 2006 15:18:50 -0700 Subject: [IPV4]: ip_options_fragment() has no effect on fragmentation Fix error point to options in ip_options_fragment(). optptr get a error pointer to the ipv4 header, correct is pointer to ipv4 options. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/ipv4/ip_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 9bebad07bf2e..cbcae6544622 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -209,7 +209,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) void ip_options_fragment(struct sk_buff * skb) { - unsigned char * optptr = skb->nh.raw; + unsigned char * optptr = skb->nh.raw + sizeof(struct iphdr); struct ip_options * opt = &(IPCB(skb)->opt); int l = opt->optlen; int optlen; -- cgit v1.2.2 From f07d5b946510a54937a75a3654941e855ffdc4c2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 9 May 2006 15:23:03 -0700 Subject: [NET]: Make netdev_chain a raw notifier. From: Alan Stern This chain does it's own locking via the RTNL semaphore, and can also run recursively so adding a new mutex here was causing deadlocks. Signed-off-by: David S. Miller --- net/core/dev.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 9ab3cfa58466..ced57430f6d8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -193,7 +193,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex) * Our notifier list */ -static BLOCKING_NOTIFIER_HEAD(netdev_chain); +static RAW_NOTIFIER_HEAD(netdev_chain); /* * Device drivers call our routines to queue packets here. We empty the @@ -736,7 +736,7 @@ int dev_change_name(struct net_device *dev, char *newname) if (!err) { hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); } @@ -751,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname) */ void netdev_features_change(struct net_device *dev) { - blocking_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); } EXPORT_SYMBOL(netdev_features_change); @@ -766,7 +766,7 @@ EXPORT_SYMBOL(netdev_features_change); void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } @@ -864,7 +864,7 @@ int dev_open(struct net_device *dev) /* * ... and announce new interface. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return ret; } @@ -887,7 +887,7 @@ int dev_close(struct net_device *dev) * Tell people we are going down, so that they can * prepare to death, when device is still operating. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); dev_deactivate(dev); @@ -924,7 +924,7 @@ int dev_close(struct net_device *dev) /* * Tell people we are down */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); return 0; } @@ -955,7 +955,7 @@ int register_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = blocking_notifier_chain_register(&netdev_chain, nb); + err = raw_notifier_chain_register(&netdev_chain, nb); if (!err) { for (dev = dev_base; dev; dev = dev->next) { nb->notifier_call(nb, NETDEV_REGISTER, dev); @@ -983,7 +983,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = blocking_notifier_chain_unregister(&netdev_chain, nb); + err = raw_notifier_chain_unregister(&netdev_chain, nb); rtnl_unlock(); return err; } @@ -994,12 +994,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb) * @v: pointer passed unmodified to notifier function * * Call all network notifier blocks. Parameters and return value - * are as for blocking_notifier_call_chain(). + * are as for raw_notifier_call_chain(). */ int call_netdevice_notifiers(unsigned long val, void *v) { - return blocking_notifier_call_chain(&netdev_chain, val, v); + return raw_notifier_call_chain(&netdev_chain, val, v); } /* When > 0 there are consumers of rx skb time stamps */ @@ -2308,7 +2308,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) if (dev->flags & IFF_UP && ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { @@ -2353,7 +2353,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) else dev->mtu = new_mtu; if (!err && dev->flags & IFF_UP) - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev); return err; } @@ -2370,7 +2370,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) return -ENODEV; err = dev->set_mac_address(dev, sa); if (!err) - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return err; } @@ -2427,7 +2427,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; @@ -2882,7 +2882,7 @@ int register_netdevice(struct net_device *dev) write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); /* Finish registration after unlock */ net_set_todo(dev); @@ -2961,7 +2961,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rtnl_lock(); /* Rebroadcast unregister notification */ - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); if (test_bit(__LINK_STATE_LINKWATCH_PENDING, @@ -3216,7 +3216,7 @@ int unregister_netdevice(struct net_device *dev) /* Notify protocols, that we are about to destroy this device. They should clean all the things. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); /* * Flush the multicast chain -- cgit v1.2.2 From 11766199a0bb9a7ba57510119e7340140e7c3e24 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 9 May 2006 15:25:25 -0700 Subject: [IRDA]: Removing unused EXPORT_SYMBOLs This patch removes the following unused EXPORT_SYMBOL's: - irias_find_attrib - irias_new_string_value - irias_new_octseq_value Signed-off-by: Adrian Bunk Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- net/irda/irias_object.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c index c6d169fbdceb..82e665c79991 100644 --- a/net/irda/irias_object.c +++ b/net/irda/irias_object.c @@ -257,7 +257,6 @@ struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name) /* Unsafe (locking), attrib might change */ return attrib; } -EXPORT_SYMBOL(irias_find_attrib); /* * Function irias_add_attribute (obj, attrib) @@ -484,7 +483,6 @@ struct ias_value *irias_new_string_value(char *string) return value; } -EXPORT_SYMBOL(irias_new_string_value); /* * Function irias_new_octseq_value (octets, len) @@ -519,7 +517,6 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len) memcpy(value->t.oct_seq, octseq , len); return value; } -EXPORT_SYMBOL(irias_new_octseq_value); struct ias_value *irias_new_missing_value(void) { -- cgit v1.2.2 From 8c1056839e808aad728db86d739ffec71d2d1db8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 May 2006 15:27:54 -0700 Subject: [NET] linkwatch: Handle jiffies wrap-around The test used in the linkwatch does not handle wrap-arounds correctly. Since the intention of the code is to eliminate bursts of messages we can afford to delay things up to a second. Using that fact we can easily handle wrap-arounds by making sure that we don't delay things by more than one second. This is based on diagnosis and a patch by Stefan Rompf. Signed-off-by: Herbert Xu Acked-by: Stefan Rompf Signed-off-by: David S. Miller --- net/core/link_watch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 341de44c7ed1..646937cc2d84 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -170,13 +170,13 @@ void linkwatch_fire_event(struct net_device *dev) spin_unlock_irqrestore(&lweventlist_lock, flags); if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { - unsigned long thisevent = jiffies; + unsigned long delay = linkwatch_nextevent - jiffies; - if (thisevent >= linkwatch_nextevent) { + /* If we wrap around we'll delay it by at most HZ. */ + if (!delay || delay > HZ) schedule_work(&linkwatch_work); - } else { - schedule_delayed_work(&linkwatch_work, linkwatch_nextevent - thisevent); - } + else + schedule_delayed_work(&linkwatch_work, delay); } } } -- cgit v1.2.2 From b17a7c179dd3ce7d04373fddf660eda21efc9db9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 10 May 2006 13:21:17 -0700 Subject: [NET]: Do sysfs registration as part of register_netdevice. The last step of netdevice registration was being done by a delayed call, but because it was delayed, it was impossible to return any error code if the class_device registration failed. Side effects: * one state in registration process is unnecessary. * register_netdevice can sleep inside class_device registration/hotplug * code in netdev_run_todo only does unregistration so it is simpler. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/core/dev.c | 63 +++++++++++++++++++++++++--------------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index ced57430f6d8..2dce673a039b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2777,6 +2777,8 @@ int register_netdevice(struct net_device *dev) BUG_ON(dev_boot_phase); ASSERT_RTNL(); + might_sleep(); + /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); @@ -2863,6 +2865,11 @@ int register_netdevice(struct net_device *dev) if (!dev->rebuild_header) dev->rebuild_header = default_rebuild_header; + ret = netdev_register_sysfs(dev); + if (ret) + goto out_err; + dev->reg_state = NETREG_REGISTERED; + /* * Default initial state at registry is that the * device is present. @@ -2878,14 +2885,11 @@ int register_netdevice(struct net_device *dev) hlist_add_head(&dev->name_hlist, head); hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex)); dev_hold(dev); - dev->reg_state = NETREG_REGISTERING; write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); - /* Finish registration after unlock */ - net_set_todo(dev); ret = 0; out: @@ -3008,7 +3012,7 @@ static void netdev_wait_allrefs(struct net_device *dev) * * We are invoked by rtnl_unlock() after it drops the semaphore. * This allows us to deal with problems: - * 1) We can create/delete sysfs objects which invoke hotplug + * 1) We can delete sysfs objects which invoke hotplug * without deadlocking with linkwatch via keventd. * 2) Since we run with the RTNL semaphore not held, we can sleep * safely in order to wait for the netdev refcnt to drop to zero. @@ -3017,8 +3021,6 @@ static DEFINE_MUTEX(net_todo_run_mutex); void netdev_run_todo(void) { struct list_head list = LIST_HEAD_INIT(list); - int err; - /* Need to guard against multiple cpu's getting out of order. */ mutex_lock(&net_todo_run_mutex); @@ -3041,40 +3043,29 @@ void netdev_run_todo(void) = list_entry(list.next, struct net_device, todo_list); list_del(&dev->todo_list); - switch(dev->reg_state) { - case NETREG_REGISTERING: - err = netdev_register_sysfs(dev); - if (err) - printk(KERN_ERR "%s: failed sysfs registration (%d)\n", - dev->name, err); - dev->reg_state = NETREG_REGISTERED; - break; - - case NETREG_UNREGISTERING: - netdev_unregister_sysfs(dev); - dev->reg_state = NETREG_UNREGISTERED; - - netdev_wait_allrefs(dev); + if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { + printk(KERN_ERR "network todo '%s' but state %d\n", + dev->name, dev->reg_state); + dump_stack(); + continue; + } - /* paranoia */ - BUG_ON(atomic_read(&dev->refcnt)); - BUG_TRAP(!dev->ip_ptr); - BUG_TRAP(!dev->ip6_ptr); - BUG_TRAP(!dev->dn_ptr); + netdev_unregister_sysfs(dev); + dev->reg_state = NETREG_UNREGISTERED; + netdev_wait_allrefs(dev); - /* It must be the very last action, - * after this 'dev' may point to freed up memory. - */ - if (dev->destructor) - dev->destructor(dev); - break; + /* paranoia */ + BUG_ON(atomic_read(&dev->refcnt)); + BUG_TRAP(!dev->ip_ptr); + BUG_TRAP(!dev->ip6_ptr); + BUG_TRAP(!dev->dn_ptr); - default: - printk(KERN_ERR "network todo '%s' but state %d\n", - dev->name, dev->reg_state); - break; - } + /* It must be the very last action, + * after this 'dev' may point to freed up memory. + */ + if (dev->destructor) + dev->destructor(dev); } out: -- cgit v1.2.2 From ac05202e8b83594bf6797d241371e6c752f371e6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 10 May 2006 13:21:53 -0700 Subject: [BRIDGE]: Do sysfs registration inside rtnl. Now that netdevice sysfs registration is done as part of register_netdevice; bridge code no longer has to be tricky when adding it's kobjects to bridges. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 59eef42d4a42..ad1c7af65ec8 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -308,26 +308,19 @@ int br_add_bridge(const char *name) if (ret) goto err2; - /* network device kobject is not setup until - * after rtnl_unlock does it's hotplug magic. - * so hold reference to avoid race. - */ - dev_hold(dev); - rtnl_unlock(); - ret = br_sysfs_addbr(dev); - dev_put(dev); - - if (ret) - unregister_netdev(dev); - out: - return ret; + if (ret) + goto err3; + rtnl_unlock(); + return 0; + err3: + unregister_netdev(dev); err2: free_netdev(dev); err1: rtnl_unlock(); - goto out; + return ret; } int br_del_bridge(const char *name) -- cgit v1.2.2 From b0013fd47b14fc26eec07a6b2cec0c2a8954e1d7 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Wed, 10 May 2006 13:24:38 -0700 Subject: [IPV6]: skb leakage in inet6_csk_xmit inet6_csk_xit does not free skb when routing fails. Signed-off-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- net/ipv6/inet6_connection_sock.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index f8f3a37a1494..eb2865d5ae28 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -173,6 +173,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) if (err) { sk->sk_err_soft = -err; + kfree_skb(skb); return err; } @@ -181,6 +182,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { sk->sk_route_caps = 0; + kfree_skb(skb); return err; } -- cgit v1.2.2 From 210525d65d33d17eb6bea6c965ce442d60d9aa8d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 May 2006 12:22:03 -0700 Subject: [NET_SCHED]: HFSC: fix thinko in hfsc_adjust_levels() When deleting the last child the level of a class should drop to zero. Noticed by Andreas Mueller Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_hfsc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 91132f6871d7..f1c7bd29f2cd 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -974,10 +974,10 @@ hfsc_adjust_levels(struct hfsc_class *cl) do { level = 0; list_for_each_entry(p, &cl->children, siblings) { - if (p->level > level) - level = p->level; + if (p->level >= level) + level = p->level + 1; } - cl->level = level + 1; + cl->level = level; } while ((cl = cl->cl_parent) != NULL); } -- cgit v1.2.2 From bd89efc532fe41f867f848144cc8b42054ddf6f9 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 12 May 2006 14:56:08 -0700 Subject: [NEIGH]: Fix IP-over-ATM and ARP interaction. The classical IP over ATM code maintains its own IPv4 <-> ARP table, using the standard neighbour-table code. The neigh_table_init function adds this neighbour table to a linked list of all neighbor tables which is used by the functions neigh_delete() neigh_add() and neightbl_set(), all called by the netlink code. Once the ATM neighbour table is added to the list, there are two tables with family == AF_INET there, and ARP entries sent via netlink go into the first table with matching family. This is indeterminate and often wrong. To see the bug, on a kernel with CLIP enabled, create a standard IPv4 ARP entry by pinging an unused address on a local subnet. Then attempt to complete that entry by doing ip neigh replace lladdr nud reachable Looking at the ARP tables by using ip neigh show will reveal two ARP entries for the same address. One of these can be found in /proc/net/arp, and the other in /proc/net/atm/arp. This patch adds a new function, neigh_table_init_no_netlink() which does everything the neigh_table_init() does, except add the table to the netlink all-arp-tables chain. In addition neigh_table_init() has a check that all tables on the chain have a distinct address family. The init call in clip.c is changed to call neigh_table_init_no_netlink(). Since ATM ARP tables are rather more complicated than can currently be handled by the available rtattrs in the netlink protocol, no functionality is lost by this patch, and non-ATM ARP manipulation via netlink is rescued. A more complete solution would involve a rtattr for ATM ARP entries and some way for the netlink code to give neigh_add and friends more information than just address family with which to find the correct ARP table. [ I've changed the assertion checking in neigh_table_init() to not use BUG_ON() while holding neigh_tbl_lock. Instead we remember that we found an existing tbl with the same family, and after dropping the lock we'll give a diagnostic kernel log message and a stack dump. -DaveM ] Signed-off-by: Simon Kelley Signed-off-by: David S. Miller --- net/atm/clip.c | 2 +- net/core/neighbour.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/atm/clip.c b/net/atm/clip.c index 1a786bfaa416..72d852982664 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -963,7 +963,7 @@ static struct file_operations arp_seq_fops = { static int __init atm_clip_init(void) { struct proc_dir_entry *p; - neigh_table_init(&clip_tbl); + neigh_table_init_no_netlink(&clip_tbl); clip_tbl_hook = &clip_tbl; register_atm_ioctl(&clip_ioctl_ops); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 4cf878efdb49..50a8c73caf97 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1326,8 +1326,7 @@ void neigh_parms_destroy(struct neigh_parms *parms) kfree(parms); } - -void neigh_table_init(struct neigh_table *tbl) +void neigh_table_init_no_netlink(struct neigh_table *tbl) { unsigned long now = jiffies; unsigned long phsize; @@ -1383,10 +1382,27 @@ void neigh_table_init(struct neigh_table *tbl) tbl->last_flush = now; tbl->last_rand = now + tbl->parms.reachable_time * 20; +} + +void neigh_table_init(struct neigh_table *tbl) +{ + struct neigh_table *tmp; + + neigh_table_init_no_netlink(tbl); write_lock(&neigh_tbl_lock); + for (tmp = neigh_tables; tmp; tmp = tmp->next) { + if (tmp->family == tbl->family) + break; + } tbl->next = neigh_tables; neigh_tables = tbl; write_unlock(&neigh_tbl_lock); + + if (unlikely(tmp)) { + printk(KERN_ERR "NEIGH: Registering multiple tables for " + "family %d\n", tbl->family); + dump_stack(); + } } int neigh_table_clear(struct neigh_table *tbl) @@ -2657,6 +2673,7 @@ EXPORT_SYMBOL(neigh_rand_reach_time); EXPORT_SYMBOL(neigh_resolve_output); EXPORT_SYMBOL(neigh_table_clear); EXPORT_SYMBOL(neigh_table_init); +EXPORT_SYMBOL(neigh_table_init_no_netlink); EXPORT_SYMBOL(neigh_update); EXPORT_SYMBOL(neigh_update_hhs); EXPORT_SYMBOL(pneigh_enqueue); -- cgit v1.2.2 From 338f7566e5c26a9547e25d54863ae4e4e5c856d1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 16 May 2006 15:02:12 -0700 Subject: [PKT_SCHED]: Potential jiffy wrap bug in dev_watchdog(). There is a potential jiffy wraparound bug in the transmit watchdog that is easily avoided by using time_after(). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 31eb83717c26..138ea92ed268 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -193,8 +193,10 @@ static void dev_watchdog(unsigned long arg) netif_running(dev) && netif_carrier_ok(dev)) { if (netif_queue_stopped(dev) && - (jiffies - dev->trans_start) > dev->watchdog_timeo) { - printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name); + time_after(jiffies, dev->trans_start + dev->watchdog_timeo)) { + + printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", + dev->name); dev->tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo)) -- cgit v1.2.2 From 53d42f541278b6c97724465b19bae4730d7a85c8 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 16 May 2006 15:07:28 -0700 Subject: [IPX]: Correct argument type of ipxrtr_delete(). A single caller passes __u32. Inside function "net" is compared with __u32 (__be32 really, just wasn't annotated). Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipx/ipx_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c index 67774448efd9..a394c6fe19a2 100644 --- a/net/ipx/ipx_route.c +++ b/net/ipx/ipx_route.c @@ -119,7 +119,7 @@ out: return rc; } -static int ipxrtr_delete(long net) +static int ipxrtr_delete(__u32 net) { struct ipx_route *r, *tmp; int rc; -- cgit v1.2.2 From 4ac396c0467993853d3d58c0975151515700c07b Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 16 May 2006 15:17:49 -0700 Subject: [IPX]: Correct return type of ipx_map_frame_type(). Casting BE16 to int and back may or may not work. Correct, to be sure. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipx/af_ipx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 2dbf134d5266..811d998725bc 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -944,9 +944,9 @@ out: return rc; } -static int ipx_map_frame_type(unsigned char type) +static __be16 ipx_map_frame_type(unsigned char type) { - int rc = 0; + __be16 rc = 0; switch (type) { case IPX_FRAME_ETHERII: rc = htons(ETH_P_IPX); break; -- cgit v1.2.2 From 6599519e9c6c56ff0f9a4ffd53f90c5b65b902f4 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 16 May 2006 15:23:40 -0700 Subject: [TR]: Remove an unused export. This patch removes the unused EXPORT_SYMBOL(tr_source_route). (Note, the usage in net/llc/llc_output.c can't be modular.) Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/802/tr.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/802/tr.c b/net/802/tr.c index afd8385c0c9c..e9dc803f2fe0 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -643,6 +643,5 @@ static int __init rif_init(void) module_init(rif_init); -EXPORT_SYMBOL(tr_source_route); EXPORT_SYMBOL(tr_type_trans); EXPORT_SYMBOL(alloc_trdev); -- cgit v1.2.2 From d8fd0a73169e90022dc3ccf3083ca24573b44b5c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 16 May 2006 15:24:41 -0700 Subject: [IPV6]: Endian fix in net/ipv6/netfilter/ip6t_eui64.c:match(). Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipv6/netfilter/ip6t_eui64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index 94dbdb8b458d..4f6b84c8f4ab 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c @@ -40,7 +40,7 @@ match(const struct sk_buff *skb, memset(eui64, 0, sizeof(eui64)); - if (eth_hdr(skb)->h_proto == ntohs(ETH_P_IPV6)) { + if (eth_hdr(skb)->h_proto == htons(ETH_P_IPV6)) { if (skb->nh.ipv6h->version == 0x6) { memcpy(eui64, eth_hdr(skb)->h_source, 3); memcpy(eui64 + 5, eth_hdr(skb)->h_source + 3, 3); -- cgit v1.2.2 From 8872d8e1c4311dd7e5086975df9c76120a0be83b Mon Sep 17 00:00:00 2001 From: "Angelo P. Castellani" Date: Tue, 16 May 2006 21:42:11 -0700 Subject: [TCP]: reno sacked_out count fix From: "Angelo P. Castellani" Using NewReno, if a sk_buff is timed out and is accounted as lost_out, it should also be removed from the sacked_out. This is necessary because recovery using NewReno fast retransmit could take up to a lot RTTs and the sk_buff RTO can expire without actually being really lost. left_out = sacked_out + lost_out in_flight = packets_out - left_out + retrans_out Using NewReno without this patch, on very large network losses, left_out becames bigger than packets_out + retrans_out (!!). For this reason unsigned integer in_flight overflows to 2^32 - something. Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9f0cca4c4fae..4a538bc1683d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1662,6 +1662,8 @@ static void tcp_update_scoreboard(struct sock *sk, struct tcp_sock *tp) if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); + if (IsReno(tp)) + tcp_remove_reno_sacks(sk, tp, tcp_skb_pcount(skb) + 1); /* clear xmit_retrans hint */ if (tp->retransmit_skb_hint && -- cgit v1.2.2 From 493e2428aa1db0e592736ad15885c6ed1e81b8af Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 19 May 2006 02:15:13 -0700 Subject: [NETFILTER]: Fix memory leak in ipt_recent The Coverity checker spotted that we may leak 'hold' in net/ipv4/netfilter/ipt_recent.c::checkentry() when the following is true: if (!curr_table->status_proc) { ... if(!curr_table) { ... return 0; <-- here we leak. Simply moving an existing vfree(hold); up a bit avoids the possible leak. Signed-off-by: Jesper Juhl Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_recent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 143843285702..b847ee409efb 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -821,6 +821,7 @@ checkentry(const char *tablename, /* Create our proc 'status' entry. */ curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent); if (!curr_table->status_proc) { + vfree(hold); printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n"); /* Destroy the created table */ spin_lock_bh(&recent_lock); @@ -845,7 +846,6 @@ checkentry(const char *tablename, spin_unlock_bh(&recent_lock); vfree(curr_table->time_info); vfree(curr_table->hash_table); - vfree(hold); vfree(curr_table->table); vfree(curr_table); return 0; -- cgit v1.2.2 From 5c170a09d9092e63af1658179f29867d32d56b55 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 19 May 2006 02:15:47 -0700 Subject: [NETFILTER]: fix format specifier for netfilter log targets The prefix argument for nf_log_packet is a format specifier, so don't pass the user defined string directly to it. Signed-off-by: Philip Craig Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/bridge/netfilter/ebt_log.c | 2 +- net/ipv4/netfilter/ipt_LOG.c | 2 +- net/ipv6/netfilter/ip6t_LOG.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index d159c92cca84..466ed3440b74 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -168,7 +168,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr, if (info->bitmask & EBT_LOG_NFLOG) nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li, - info->prefix); + "%s", info->prefix); else ebt_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li, info->prefix); diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 39fd4c2a2386..b98f7b08b084 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -428,7 +428,7 @@ ipt_log_target(struct sk_buff **pskb, if (loginfo->logflags & IPT_LOG_NFLOG) nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - loginfo->prefix); + "%s", loginfo->prefix); else ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, loginfo->prefix); diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index a96c0de14b00..73c6300109d6 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -439,7 +439,7 @@ ip6t_log_target(struct sk_buff **pskb, if (loginfo->logflags & IP6T_LOG_NFLOG) nf_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, - loginfo->prefix); + "%s", loginfo->prefix); else ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, loginfo->prefix); -- cgit v1.2.2 From a467704dcb4fa45da48079486f1b0e6baffb12d2 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 19 May 2006 02:16:29 -0700 Subject: [NETFILTER]: GRE conntrack: fix htons/htonl confusion GRE keys are 16 bit. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_proto_gre.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index 6c4899d8046a..96ceabaec402 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -49,15 +49,15 @@ gre_in_range(const struct ip_conntrack_tuple *tuple, const union ip_conntrack_manip_proto *min, const union ip_conntrack_manip_proto *max) { - u_int32_t key; + __be16 key; if (maniptype == IP_NAT_MANIP_SRC) key = tuple->src.u.gre.key; else key = tuple->dst.u.gre.key; - return ntohl(key) >= ntohl(min->gre.key) - && ntohl(key) <= ntohl(max->gre.key); + return ntohs(key) >= ntohs(min->gre.key) + && ntohs(key) <= ntohs(max->gre.key); } /* generate unique tuple ... */ @@ -81,14 +81,14 @@ gre_unique_tuple(struct ip_conntrack_tuple *tuple, min = 1; range_size = 0xffff; } else { - min = ntohl(range->min.gre.key); - range_size = ntohl(range->max.gre.key) - min + 1; + min = ntohs(range->min.gre.key); + range_size = ntohs(range->max.gre.key) - min + 1; } DEBUGP("min = %u, range_size = %u\n", min, range_size); for (i = 0; i < range_size; i++, key++) { - *keyptr = htonl(min + key % range_size); + *keyptr = htons(min + key % range_size); if (!ip_nat_used_tuple(tuple, conntrack)) return 1; } -- cgit v1.2.2 From 2c8ac66bb2ff89e759f0d632a27cc64205e9ddd9 Mon Sep 17 00:00:00 2001 From: Solar Designer Date: Fri, 19 May 2006 02:16:52 -0700 Subject: [NETFILTER]: Fix do_add_counters race, possible oops or info leak (CVE-2006-0039) Solar Designer found a race condition in do_add_counters(). The beginning of paddc is supposed to be the same as tmp which was sanity-checked above, but it might not be the same in reality. In case the integer overflow and/or the race condition are triggered, paddc->num_counters might not match the allocation size for paddc. If the check below (t->private->number != paddc->num_counters) nevertheless passes (perhaps this requires the race condition to be triggered), IPT_ENTRY_ITERATE() would read kernel memory beyond the allocation size, potentially causing an oops or leaking sensitive data (e.g., passwords from host system or from another VPS) via counter increments. This requires CAP_NET_ADMIN. Signed-off-by: Solar Designer Signed-off-by: Kirill Korotaev Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/arp_tables.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index c2d92f99a2b8..d0d19192026d 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -948,7 +948,7 @@ static int do_add_counters(void __user *user, unsigned int len) write_lock_bh(&t->lock); private = t->private; - if (private->number != paddc->num_counters) { + if (private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 0a673038344f..2e72f89a7019 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1103,7 +1103,7 @@ do_add_counters(void __user *user, unsigned int len) write_lock_bh(&t->lock); private = t->private; - if (private->number != paddc->num_counters) { + if (private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } -- cgit v1.2.2 From ee433530d96a7b0af24ab616e5b51f1d89f9ae38 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 19 May 2006 02:17:18 -0700 Subject: [NETFILTER]: nfnetlink_log: fix byteorder confusion flags is a u16, so use htons instead of htonl. Also avoid double conversion. Noticed by Alexey Dobriyan Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nfnetlink_log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index c60273cad778..61cdda4e5d3b 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -321,7 +321,7 @@ static int nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags) { spin_lock_bh(&inst->lock); - inst->flags = ntohs(flags); + inst->flags = flags; spin_unlock_bh(&inst->lock); return 0; @@ -902,7 +902,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, if (nfula[NFULA_CFG_FLAGS-1]) { u_int16_t flags = *(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]); - nfulnl_set_flags(inst, ntohl(flags)); + nfulnl_set_flags(inst, ntohs(flags)); } out_put: -- cgit v1.2.2 From 8de8c8738086501bbe3057ed6f4b70dded657488 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Fri, 19 May 2006 10:58:12 -0700 Subject: [SCTP]: Set sk_err so that poll wakes up after a non-blocking connect failure. Also fix some other cases where sk_err is not set for 1-1 style sockets. Signed-off-by: Sridhar Samudrala --- net/sctp/input.c | 4 +-- net/sctp/sm_sideeffect.c | 16 ++++++++--- net/sctp/sm_statefuns.c | 75 +++++++++++++++++++++++++++++++----------------- net/sctp/socket.c | 1 + 4 files changed, 63 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/net/sctp/input.c b/net/sctp/input.c index d117ebc75cf8..7523f4df2da6 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -412,7 +412,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, union sctp_addr daddr; struct sctp_af *af; struct sock *sk = NULL; - struct sctp_association *asoc = NULL; + struct sctp_association *asoc; struct sctp_transport *transport = NULL; *app = NULL; *tpp = NULL; @@ -490,7 +490,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct sock *sk; - struct sctp_association *asoc; + struct sctp_association *asoc = NULL; struct sctp_transport *transport; struct inet_sock *inet; char *saveip, *savesctp; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 8d1dc24bab4c..c5beb2ad7ef7 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -498,10 +498,6 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); - /* Set sk_err to ECONNRESET on a 1-1 style socket. */ - if (!sctp_style(asoc->base.sk, UDP)) - asoc->base.sk->sk_err = ECONNRESET; - /* SEND_FAILED sent later when cleaning up the association. */ asoc->outqueue.error = error; sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); @@ -838,6 +834,15 @@ static void sctp_cmd_del_non_primary(struct sctp_association *asoc) return; } +/* Helper function to set sk_err on a 1-1 style socket. */ +static void sctp_cmd_set_sk_err(struct sctp_association *asoc, int error) +{ + struct sock *sk = asoc->base.sk; + + if (!sctp_style(sk, UDP)) + sk->sk_err = error; +} + /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -1458,6 +1463,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, local_cork = 0; asoc->peer.retran_path = t; break; + case SCTP_CMD_SET_SK_ERR: + sctp_cmd_set_sk_err(asoc, cmd->obj.error); + break; default: printk(KERN_WARNING "Impossible command: %u, %p\n", cmd->verb, cmd->obj.ptr); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 8cdba51ec076..174f7a7c6cd1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -93,7 +93,7 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk); static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, - __u16 error, + __u16 error, int sk_err, const struct sctp_association *asoc, struct sctp_transport *transport); @@ -448,7 +448,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, __u32 init_tag; struct sctp_chunk *err_chunk; struct sctp_packet *packet; - sctp_disposition_t ret; + __u16 error; if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -480,11 +480,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_CLOSED)); - SCTP_INC_STATS(SCTP_MIB_ABORTEDS); - sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - return SCTP_DISPOSITION_DELETE_TCB; + return sctp_stop_t1_and_abort(commands, SCTP_ERROR_INV_PARAM, + ECONNREFUSED, asoc, + chunk->transport); } /* Verify the INIT chunk before processing it. */ @@ -511,27 +509,16 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_CLOSED)); - sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, - SCTP_NULL()); - return SCTP_DISPOSITION_CONSUME; + error = SCTP_ERROR_INV_PARAM; } else { - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_CLOSED)); - sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, - SCTP_NULL()); - return SCTP_DISPOSITION_NOMEM; + error = SCTP_ERROR_NO_RESOURCE; } } else { - ret = sctp_sf_tabort_8_4_8(ep, asoc, type, arg, - commands); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_CLOSED)); - sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, - SCTP_NULL()); - return ret; + sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); + error = SCTP_ERROR_INV_PARAM; } + return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, + asoc, chunk->transport); } /* Tag the variable length parameters. Note that we never @@ -886,6 +873,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, struct sctp_transport *transport = (struct sctp_transport *) arg; if (asoc->overall_error_count >= asoc->max_retrans) { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); @@ -2126,6 +2115,8 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep, int attempts = asoc->init_err_counter + 1; if (attempts > asoc->max_init_attempts) { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_STALE_COOKIE)); return SCTP_DISPOSITION_DELETE_TCB; @@ -2262,6 +2253,7 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep, if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET)); /* ASSOC_FAILED will DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error)); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); @@ -2306,7 +2298,8 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep, if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; - return sctp_stop_t1_and_abort(commands, error, asoc, chunk->transport); + return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, asoc, + chunk->transport); } /* @@ -2318,7 +2311,8 @@ sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep void *arg, sctp_cmd_seq_t *commands) { - return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR, asoc, + return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR, + ENOPROTOOPT, asoc, (struct sctp_transport *)arg); } @@ -2343,7 +2337,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep, * This is common code called by several sctp_sf_*_abort() functions above. */ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, - __u16 error, + __u16 error, int sk_err, const struct sctp_association *asoc, struct sctp_transport *transport) { @@ -2353,6 +2347,7 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, SCTP_INC_STATS(SCTP_MIB_ABORTEDS); sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(sk_err)); /* CMD_INIT_FAILED will DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error)); @@ -3336,6 +3331,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNABORTED)); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_ASCONF_ACK)); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); @@ -3362,6 +3359,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNABORTED)); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_ASCONF_ACK)); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); @@ -3714,9 +3713,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen( if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNREFUSED)); sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_PROTO_VIOLATION)); } else { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNABORTED)); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_PROTO_VIOLATION)); SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); @@ -4034,6 +4037,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort( * TCB. This is a departure from our typical NOMEM handling. */ + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNABORTED)); /* Delete the established association. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_USER_ABORT)); @@ -4175,6 +4180,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort( * TCB. This is a departure from our typical NOMEM handling. */ + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNREFUSED)); /* Delete the established association. */ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_USER_ABORT)); @@ -4543,6 +4550,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, struct sctp_transport *transport = arg; if (asoc->overall_error_count >= asoc->max_retrans) { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); @@ -4662,6 +4671,8 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep, SCTP_DEBUG_PRINTK("Giving up on INIT, attempts: %d" " max_init_attempts: %d\n", attempts, asoc->max_init_attempts); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); return SCTP_DISPOSITION_DELETE_TCB; @@ -4711,6 +4722,8 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); } else { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); return SCTP_DISPOSITION_DELETE_TCB; @@ -4742,6 +4755,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); if (asoc->overall_error_count >= asoc->max_retrans) { + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); @@ -4817,6 +4832,8 @@ sctp_disposition_t sctp_sf_t4_timer_expire( if (asoc->overall_error_count >= asoc->max_retrans) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); @@ -4870,6 +4887,8 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep, goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ETIMEDOUT)); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); @@ -5309,6 +5328,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, + SCTP_ERROR(ECONNABORTED)); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_DATA)); SCTP_INC_STATS(SCTP_MIB_ABORTEDS); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b6e4b89539b3..90863307bcd9 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1057,6 +1057,7 @@ static int __sctp_connect(struct sock* sk, inet_sk(sk)->dport = htons(asoc->peer.port); af = sctp_get_af_specific(to.sa.sa_family); af->to_sk_daddr(&to, sk); + sk->sk_err = 0; timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); -- cgit v1.2.2 From 61c9fed41638249f8b6ca5345064eb1beb50179f Mon Sep 17 00:00:00 2001 From: Vladislav Yasevich Date: Fri, 19 May 2006 11:01:18 -0700 Subject: [SCTP]: A better solution to fix the race between sctp_peeloff() and sctp_rcv(). The goal is to hold the ref on the association/endpoint throughout the state-machine process. We accomplish like this: /* ref on the assoc/ep is taken during lookup */ if owned_by_user(sk) sctp_add_backlog(skb, sk); else inqueue_push(skb, sk); /* drop the ref on the assoc/ep */ However, in sctp_add_backlog() we take the ref on assoc/ep and hold it while the skb is on the backlog queue. This allows us to get rid of the sock_hold/sock_put in the lookup routines. Now sctp_backlog_rcv() needs to account for potential association move. In the unlikely event that association moved, we need to retest if the new socket is locked by user. If we don't this, we may have two packets racing up the stack toward the same socket and we can't deal with it. If the new socket is still locked, we'll just add the skb to its backlog continuing to hold the ref on the association. This get's rid of the need to move packets from one backlog to another and it also safe in case new packets arrive on the same backlog queue. The last step, is to lock the new socket when we are moving the association to it. This is needed in case any new packets arrive on the association when it moved. We want these to go to the backlog since we would like to avoid the race between this new packet and a packet that may be sitting on the backlog queue of the old socket toward the same association. Signed-off-by: Vladislav Yasevich Signed-off-by: Sridhar Samudrala --- net/sctp/input.c | 140 ++++++++++++++++++++++++++++++------------------------ net/sctp/socket.c | 16 ++++--- 2 files changed, 89 insertions(+), 67 deletions(-) (limited to 'net') diff --git a/net/sctp/input.c b/net/sctp/input.c index 7523f4df2da6..1662f9cc869e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -73,6 +73,8 @@ static struct sctp_association *__sctp_lookup_association( const union sctp_addr *peer, struct sctp_transport **pt); +static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb); + /* Calculate the SCTP checksum of an SCTP packet. */ static inline int sctp_rcv_checksum(struct sk_buff *skb) @@ -186,7 +188,6 @@ int sctp_rcv(struct sk_buff *skb) */ if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) { - sock_put(sk); if (asoc) { sctp_association_put(asoc); asoc = NULL; @@ -197,7 +198,6 @@ int sctp_rcv(struct sk_buff *skb) sk = sctp_get_ctl_sock(); ep = sctp_sk(sk)->ep; sctp_endpoint_hold(ep); - sock_hold(sk); rcvr = &ep->base; } @@ -253,25 +253,18 @@ int sctp_rcv(struct sk_buff *skb) */ sctp_bh_lock_sock(sk); - /* It is possible that the association could have moved to a different - * socket if it is peeled off. If so, update the sk. - */ - if (sk != rcvr->sk) { - sctp_bh_lock_sock(rcvr->sk); - sctp_bh_unlock_sock(sk); - sk = rcvr->sk; - } - if (sock_owned_by_user(sk)) - sk_add_backlog(sk, skb); + sctp_add_backlog(sk, skb); else - sctp_backlog_rcv(sk, skb); + sctp_inq_push(&chunk->rcvr->inqueue, chunk); - /* Release the sock and the sock ref we took in the lookup calls. - * The asoc/ep ref will be released in sctp_backlog_rcv. - */ sctp_bh_unlock_sock(sk); - sock_put(sk); + + /* Release the asoc/ep ref we took in the lookup calls. */ + if (asoc) + sctp_association_put(asoc); + else + sctp_endpoint_put(ep); return 0; @@ -280,8 +273,7 @@ discard_it: return 0; discard_release: - /* Release any structures we may be holding. */ - sock_put(sk); + /* Release the asoc/ep ref we took in the lookup calls. */ if (asoc) sctp_association_put(asoc); else @@ -290,56 +282,87 @@ discard_release: goto discard_it; } -/* Handle second half of inbound skb processing. If the sock was busy, - * we may have need to delay processing until later when the sock is - * released (on the backlog). If not busy, we call this routine - * directly from the bottom half. +/* Process the backlog queue of the socket. Every skb on + * the backlog holds a ref on an association or endpoint. + * We hold this ref throughout the state machine to make + * sure that the structure we need is still around. */ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; - struct sctp_inq *inqueue = NULL; + struct sctp_inq *inqueue = &chunk->rcvr->inqueue; struct sctp_ep_common *rcvr = NULL; + int backloged = 0; rcvr = chunk->rcvr; - BUG_TRAP(rcvr->sk == sk); - - if (rcvr->dead) { - sctp_chunk_free(chunk); - } else { - inqueue = &chunk->rcvr->inqueue; - sctp_inq_push(inqueue, chunk); - } - - /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */ - if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) - sctp_association_put(sctp_assoc(rcvr)); - else - sctp_endpoint_put(sctp_ep(rcvr)); - + /* If the rcvr is dead then the association or endpoint + * has been deleted and we can safely drop the chunk + * and refs that we are holding. + */ + if (rcvr->dead) { + sctp_chunk_free(chunk); + goto done; + } + + if (unlikely(rcvr->sk != sk)) { + /* In this case, the association moved from one socket to + * another. We are currently sitting on the backlog of the + * old socket, so we need to move. + * However, since we are here in the process context we + * need to take make sure that the user doesn't own + * the new socket when we process the packet. + * If the new socket is user-owned, queue the chunk to the + * backlog of the new socket without dropping any refs. + * Otherwise, we can safely push the chunk on the inqueue. + */ + + sk = rcvr->sk; + sctp_bh_lock_sock(sk); + + if (sock_owned_by_user(sk)) { + sk_add_backlog(sk, skb); + backloged = 1; + } else + sctp_inq_push(inqueue, chunk); + + sctp_bh_unlock_sock(sk); + + /* If the chunk was backloged again, don't drop refs */ + if (backloged) + return 0; + } else { + sctp_inq_push(inqueue, chunk); + } + +done: + /* Release the refs we took in sctp_add_backlog */ + if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) + sctp_association_put(sctp_assoc(rcvr)); + else if (SCTP_EP_TYPE_SOCKET == rcvr->type) + sctp_endpoint_put(sctp_ep(rcvr)); + else + BUG(); + return 0; } -void sctp_backlog_migrate(struct sctp_association *assoc, - struct sock *oldsk, struct sock *newsk) +static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb) { - struct sk_buff *skb; - struct sctp_chunk *chunk; + struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; + struct sctp_ep_common *rcvr = chunk->rcvr; - skb = oldsk->sk_backlog.head; - oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL; - while (skb != NULL) { - struct sk_buff *next = skb->next; - - chunk = SCTP_INPUT_CB(skb)->chunk; - skb->next = NULL; - if (&assoc->base == chunk->rcvr) - sk_add_backlog(newsk, skb); - else - sk_add_backlog(oldsk, skb); - skb = next; - } + /* Hold the assoc/ep while hanging on the backlog queue. + * This way, we know structures we need will not disappear from us + */ + if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) + sctp_association_hold(sctp_assoc(rcvr)); + else if (SCTP_EP_TYPE_SOCKET == rcvr->type) + sctp_endpoint_hold(sctp_ep(rcvr)); + else + BUG(); + + sk_add_backlog(sk, skb); } /* Handle icmp frag needed error. */ @@ -453,7 +476,6 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, return sk; out: - sock_put(sk); if (asoc) sctp_association_put(asoc); return NULL; @@ -463,7 +485,6 @@ out: void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) { sctp_bh_unlock_sock(sk); - sock_put(sk); if (asoc) sctp_association_put(asoc); } @@ -716,7 +737,6 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l hit: sctp_endpoint_hold(ep); - sock_hold(epb->sk); read_unlock(&head->lock); return ep; } @@ -818,7 +838,6 @@ static struct sctp_association *__sctp_lookup_association( hit: *pt = transport; sctp_association_hold(asoc); - sock_hold(epb->sk); read_unlock(&head->lock); return asoc; } @@ -846,7 +865,6 @@ int sctp_has_association(const union sctp_addr *laddr, struct sctp_transport *transport; if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { - sock_put(asoc->base.sk); sctp_association_put(asoc); return 1; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 90863307bcd9..b1a17758003a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1229,7 +1229,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ep = sctp_sk(sk)->ep; - /* Walk all associations on a socket, not on an endpoint. */ + /* Walk all associations on an endpoint. */ list_for_each_safe(pos, temp, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); @@ -5318,6 +5318,7 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, */ sctp_release_sock(sk); current_timeo = schedule_timeout(current_timeo); + BUG_ON(sk != asoc->base.sk); sctp_lock_sock(sk); *timeo_p = current_timeo; @@ -5605,12 +5606,14 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ newsp->type = type; - spin_lock_bh(&oldsk->sk_lock.slock); - /* Migrate the backlog from oldsk to newsk. */ - sctp_backlog_migrate(assoc, oldsk, newsk); - /* Migrate the association to the new socket. */ + /* Mark the new socket "in-use" by the user so that any packets + * that may arrive on the association after we've moved it are + * queued to the backlog. This prevents a potential race between + * backlog processing on the old socket and new-packet processing + * on the new socket. + */ + sctp_lock_sock(newsk); sctp_assoc_migrate(assoc, newsk); - spin_unlock_bh(&oldsk->sk_lock.slock); /* If the association on the newsk is already closed before accept() * is called, set RCV_SHUTDOWN flag. @@ -5619,6 +5622,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsk->sk_shutdown |= RCV_SHUTDOWN; newsk->sk_state = SCTP_SS_ESTABLISHED; + sctp_release_sock(newsk); } /* This proto struct describes the ULP interface for SCTP. */ -- cgit v1.2.2 From a601266e4f3c479790f373c2e3122a766d123652 Mon Sep 17 00:00:00 2001 From: Vladislav Yasevich Date: Fri, 19 May 2006 14:25:53 -0700 Subject: [SCTP]: Validate the parameter length in HB-ACK chunk. If SCTP receives a badly formatted HB-ACK chunk, it is possible that we may access invalid memory and potentially have a buffer overflow. We should really make sure that the chunk format is what we expect, before attempting to touch the data. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala --- net/sctp/sm_statefuns.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 174f7a7c6cd1..8bc279219a72 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1019,6 +1019,12 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, commands); hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; + /* Make sure that the length of the parameter is what we expect */ + if (ntohs(hbinfo->param_hdr.length) != + sizeof(sctp_sender_hb_info_t)) { + return SCTP_DISPOSITION_DISCARD; + } + from_addr = hbinfo->daddr; link = sctp_assoc_lookup_paddr(asoc, &from_addr); -- cgit v1.2.2 From b89498a1c2941c00889dd025f52dcb653a5083bc Mon Sep 17 00:00:00 2001 From: Vladislav Yasevich Date: Fri, 19 May 2006 14:32:06 -0700 Subject: [SCTP]: Allow linger to abort 1-N style sockets. Enable SO_LINGER functionality for 1-N style sockets. The socket API draft will be clarfied to allow for this functionality. The linger settings will apply to all associations on a given socket. Signed-off-by: Vladislav Yasevich Signed-off-by: Sridhar Samudrala --- net/sctp/socket.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b1a17758003a..174d4d35e951 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1242,13 +1242,13 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) if (sctp_state(asoc, CLOSED)) { sctp_unhash_established(asoc); sctp_association_free(asoc); + continue; + } + } - } else if (sock_flag(sk, SOCK_LINGER) && - !sk->sk_lingertime) - sctp_primitive_ABORT(asoc, NULL); - else - sctp_primitive_SHUTDOWN(asoc, NULL); - } else + if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) + sctp_primitive_ABORT(asoc, NULL); + else sctp_primitive_SHUTDOWN(asoc, NULL); } -- cgit v1.2.2 From 4195f81453b9727f82bb8ceae03411b7fe52a994 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 22 May 2006 16:53:22 -0700 Subject: [NET]: Fix "ntohl(ntohs" bugs Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipv4/ipcomp.c | 2 +- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/ipcomp6.c | 2 +- net/xfrm/xfrm_input.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index cd810f41af1a..95278b22b669 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -210,7 +210,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) skb->h.icmph->code != ICMP_FRAG_NEEDED) return; - spi = ntohl(ntohs(ipch->cpi)); + spi = htonl(ntohs(ipch->cpi)); x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET); if (!x) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index f285bbf296e2..8604c747bca5 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -221,7 +221,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) if (pskb_may_pull(skb, xprth + 4 - skb->data)) { u16 *ipcomp_hdr = (u16 *)xprth; - fl->fl_ipsec_spi = ntohl(ntohs(ipcomp_hdr[1])); + fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); } break; default: diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 05eb67def39f..48636436028a 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -208,7 +208,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type != ICMPV6_DEST_UNREACH && type != ICMPV6_PKT_TOOBIG) return; - spi = ntohl(ntohs(ipcomph->cpi)); + spi = htonl(ntohs(ipcomph->cpi)); x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); if (!x) return; diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b54971059f16..891a6090cc09 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -62,7 +62,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) case IPPROTO_COMP: if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr))) return -EINVAL; - *spi = ntohl(ntohs(*(u16*)(skb->h.raw + 2))); + *spi = htonl(ntohs(*(u16*)(skb->h.raw + 2))); *seq = 0; return 0; default: -- cgit v1.2.2 From 405a42c5c8bd5731087c0ff01310731a3c1c9c24 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 22 May 2006 16:54:08 -0700 Subject: [IRDA]: fix 16/32 bit confusion Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/irda/iriap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/irda/iriap.c b/net/irda/iriap.c index 254f90746900..2d2e2b1919f4 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -544,7 +544,8 @@ static void iriap_getvaluebyclass_response(struct iriap_cb *self, { struct sk_buff *tx_skb; int n; - __u32 tmp_be32, tmp_be16; + __u32 tmp_be32; + __be16 tmp_be16; __u8 *fp; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); -- cgit v1.2.2 From f41d5bb1d9f49b03af7126d07a511facbe283a92 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 22 May 2006 16:55:14 -0700 Subject: [NETFILTER]: SNMP NAT: fix memory corruption Fix memory corruption caused by snmp_trap_decode: - When snmp_trap_decode fails before the id and address are allocated, the pointers contain random memory, but are freed by the caller (snmp_parse_mangle). - When snmp_trap_decode fails after allocating just the ID, it tries to free both address and ID, but the address pointer still contains random memory. The caller frees both ID and random memory again. - When snmp_trap_decode fails after allocating both, it frees both, and the callers frees both again. The corruption can be triggered remotely when the ip_nat_snmp_basic module is loaded and traffic on port 161 or 162 is NATed. Found by multiple testcases of the trap-app and trap-enc groups of the PROTOS c06-snmpv1 testsuite. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_snmp_basic.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index c62253845538..688a2f29fadf 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -1003,12 +1003,12 @@ static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, return 1; +err_addr_free: + kfree((unsigned long *)trap->ip_address); + err_id_free: kfree(trap->id); -err_addr_free: - kfree((unsigned long *)trap->ip_address); - return 0; } @@ -1126,11 +1126,10 @@ static int snmp_parse_mangle(unsigned char *msg, struct snmp_v1_trap trap; unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check); - /* Discard trap allocations regardless */ - kfree(trap.id); - kfree((unsigned long *)trap.ip_address); - - if (!ret) + if (ret) { + kfree(trap.id); + kfree((unsigned long *)trap.ip_address); + } else return ret; } else { -- cgit v1.2.2 From f2d395865faa2a7cd4620b07178e58cbb160ba08 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 22 May 2006 22:35:25 -0700 Subject: [PATCH] knfsd: Fix two problems that can cause rmmod nfsd to die Both cause the 'entries' count in the export cache to be non-zero at module removal time, so unregistering that cache fails and results in an oops. 1/ exp_pseudoroot (used for NFSv4 only) leaks a reference to an export entry. 2/ sunrpc_cache_update doesn't increment the entries count when it adds an entry. Thanks to "david m. richter" for triggering the problem and finding one of the bugs. Cc: "david m. richter" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/sunrpc/cache.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 3ac4193a78ed..7026b0866b7b 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -159,6 +159,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, detail->update(tmp, new); tmp->next = *head; *head = tmp; + detail->entries++; cache_get(tmp); is_new = cache_fresh_locked(tmp, new->expiry_time); cache_fresh_locked(old, 0); -- cgit v1.2.2 From 7185989db4d926dbef1a2f638c464f35599c83e0 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 23 May 2006 15:07:07 -0700 Subject: [NETFILTER]: H.323 helper: fix parser error propagation The condition "> H323_ERROR_STOP" can never be true since H323_ERROR_STOP is positive and is the highest possible return code, while real errors are negative, fix the checks. Also only abort on real errors in some spots that were just interpreting any return value != 0 as error. Fixes crashes caused by use of stale data after a parsing error occured: BUG: unable to handle kernel paging request at virtual address bfffffff printing eip: c01aa0f8 *pde = 1a801067 *pte = 00000000 Oops: 0000 [#1] PREEMPT Modules linked in: ip_nat_h323 ip_conntrack_h323 nfsd exportfs sch_sfq sch_red cls_fw sch_hfsc xt_length ipt_owner xt_MARK iptable_mangle nfs lockd sunrpc pppoe pppoxx CPU: 0 EIP: 0060:[] Not tainted VLI EFLAGS: 00210646 (2.6.17-rc4 #8) EIP is at memmove+0x19/0x22 eax: d77264e9 ebx: d77264e9 ecx: e88d9b17 edx: d77264e9 esi: bfffffff edi: bfffffff ebp: de6a7680 esp: c0349db8 ds: 007b es: 007b ss: 0068 Process asterisk (pid: 3765, threadinfo=c0349000 task=da068540) Stack: <0>00000006 c0349e5e d77264e3 e09a2b4e e09a38a0 d7726052 d7726124 00000491 00000006 00000006 00000006 00000491 de6a7680 d772601e d7726032 c0349f74 e09a2dc2 00000006 c0349e5e 00000006 00000000 d76dda28 00000491 c0349f74 Call Trace: [] mangle_contents+0x62/0xfe [ip_nat] [] ip_nat_mangle_tcp_packet+0xa1/0x191 [ip_nat] [] set_addr+0x74/0x14c [ip_nat_h323] [] process_setup+0x11b/0x29e [ip_conntrack_h323] [] process_setup+0x14c/0x29e [ip_conntrack_h323] [] process_q931+0x3c/0x142 [ip_conntrack_h323] [] q931_help+0xe0/0x144 [ip_conntrack_h323] ... Found by the PROTOS c07-h2250v4 testsuite. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c index 355a53a5b6cd..5d04438dda4b 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c @@ -528,14 +528,15 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) /* Decode */ if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) > - H323_ERROR_STOP) + level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; bs->bit = 0; } else if ((err = (Decoders[son->type]) (bs, son, base, - level + 1))) + level + 1)) < + H323_ERROR_NONE) return err; } @@ -584,8 +585,8 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) beg = bs->cur; if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) > - H323_ERROR_STOP) + level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; @@ -660,18 +661,20 @@ int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) i < effective_count ? base : NULL, - level + 1)) > - H323_ERROR_STOP) + level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; bs->bit = 0; } else - if ((err = (Decoders[son->type]) (bs, son, - i < effective_count ? - base : NULL, - level + 1))) - return err; + if ((err = (Decoders[son->type]) (bs, son, + i < + effective_count ? + base : NULL, + level + 1)) < + H323_ERROR_NONE) + return err; if (base) base += son->offset; @@ -735,13 +738,14 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) } beg = bs->cur; - if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) > - H323_ERROR_STOP) + if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1))) + } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) return err; return H323_ERROR_NONE; -- cgit v1.2.2 From 4d942d8b39bf7d43ce93d85964aeb63aeace0593 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 23 May 2006 15:07:46 -0700 Subject: [NETFILTER]: H.323 helper: fix sequence extension parsing When parsing unknown sequence extensions the "son"-pointer points behind the last known extension for this type, don't try to interpret it. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c index 5d04438dda4b..26dfecadb335 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c @@ -555,7 +555,7 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) /* Decode the extension components */ for (opt = 0; opt < bmp2_len; opt++, i++, son++) { - if (son->attr & STOP) { + if (i < f->ub && son->attr & STOP) { PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); return H323_ERROR_STOP; -- cgit v1.2.2 From 4a063739138e2c4e933188d641f1593e01ce8285 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Tue, 23 May 2006 15:08:13 -0700 Subject: [NETFILTER]: SNMP NAT: fix memleak in snmp_object_decode If kmalloc fails, error path leaks data allocated from asn1_oid_decode(). Signed-off-by: Chris Wright Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_snmp_basic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 688a2f29fadf..c33244263b90 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -768,6 +768,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, len *= sizeof(unsigned long); *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); if (*obj == NULL) { + kfree(lp); kfree(id); if (net_ratelimit()) printk("OOM in bsalg (%d)\n", __LINE__); -- cgit v1.2.2 From 387e2b0439026aa738a9edca15a57e5c0bcb4dfc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 23 May 2006 15:20:25 -0700 Subject: [BRIDGE]: need to ref count the LLC sap Bridge will OOPS on removal if other application has the SAP open. The bridge SAP might be shared with other usages, so need to do reference counting on module removal rather than explicit close/delete. Since packet might arrive after or during removal, need to clear the receive function handle, so LLC only hands it to user (if any). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/br.c b/net/bridge/br.c index 22d806cf40ca..12da21afb9ca 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -55,7 +55,7 @@ static int __init br_init(void) static void __exit br_deinit(void) { - llc_sap_close(br_stp_sap); + rcu_assign_pointer(br_stp_sap->rcv_func, NULL); #ifdef CONFIG_BRIDGE_NETFILTER br_netfilter_fini(); @@ -67,6 +67,7 @@ static void __exit br_deinit(void) synchronize_net(); + llc_sap_put(br_stp_sap); br_fdb_get_hook = NULL; br_fdb_put_hook = NULL; -- cgit v1.2.2