Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 292974 Details for
Bug 268001
bonding: Fix use after free in unregister path
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
bonding-rhel5-fixes.patch
bonding-rhel5-fixes.patch (text/plain), 13.54 KB, created by
Andy Gospodarek
on 2008-01-25 19:25:03 UTC
(
hide
)
Description:
bonding-rhel5-fixes.patch
Filename:
MIME Type:
Creator:
Andy Gospodarek
Created:
2008-01-25 19:25:03 UTC
Size:
13.54 KB
patch
obsolete
>commit b7c7229d90a01c316d1d1093b19df1761f40fd85 >Author: gospo <gospo@localhost.localdomain> >Date: Fri Jan 25 13:01:08 2008 -0500 > > Changes that will be used to sync with 2.6.24's locking fixes. > >diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c >index 09a8a89..41f7b92 100644 >--- a/drivers/net/bonding/bond_alb.c >+++ b/drivers/net/bonding/bond_alb.c >@@ -976,7 +976,7 @@ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct > /* > * Send learning packets after MAC address swap. > * >- * Called with RTNL and bond->lock held for read. >+ * Called with RTNL and no other locks > */ > static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, > struct slave *slave2) >@@ -984,6 +984,8 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, > int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); > struct slave *disabled_slave = NULL; > >+ ASSERT_RTNL(); >+ > /* fasten the change in the switch */ > if (SLAVE_IS_OK(slave1)) { > alb_send_learning_packets(slave1, slave1->dev->dev_addr); >@@ -1028,7 +1030,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, > * a slave that has @slave's permanet address as its current address. > * We'll make sure that that slave no longer uses @slave's permanent address. > * >- * Caller must hold bond lock >+ * Caller must hold RTNL and no other locks > */ > static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) > { >@@ -1539,7 +1541,12 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) > return 0; > } > >-/* Caller must hold bond lock for write */ >+/* >+ * Remove slave from tlb and rlb hash tables, and fix up MAC addresses >+ * if necessary. >+ * >+ * Caller must hold RTNL and no other locks >+ */ > void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) > { > if (bond->slave_cnt > 1) { >@@ -1598,9 +1605,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave > struct slave *swap_slave; > int i; > >- if (new_slave) >- ASSERT_RTNL(); >- > if (bond->curr_active_slave == new_slave) { > return; > } >@@ -1646,6 +1650,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave > write_unlock_bh(&bond->curr_slave_lock); > read_unlock(&bond->lock); > >+ ASSERT_RTNL(); >+ > /* curr_active_slave must be set before calling alb_swap_mac_addr */ > if (swap_slave) { > /* swap mac address */ >@@ -1656,12 +1662,11 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave > bond->alb_info.rlb_enabled); > } > >- read_lock(&bond->lock); >- > if (swap_slave) { > alb_fasten_mac_swap(bond, swap_slave, new_slave); >+ read_lock(&bond->lock); > } else { >- /* fasten bond mac on new current slave */ >+ read_lock(&bond->lock); > alb_send_learning_packets(new_slave, bond->dev->dev_addr); > } > >diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c >index 4e8048e..533b22a 100644 >--- a/drivers/net/bonding/bond_main.c >+++ b/drivers/net/bonding/bond_main.c >@@ -1751,7 +1751,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) > * has been cleared (if our_slave == old_current), > * but before a new active slave is selected. > */ >+ write_unlock_bh(&bond->lock); > bond_alb_deinit_slave(bond, slave); >+ write_lock_bh(&bond->lock); > } > > if (oldcurrent == slave) { >@@ -1910,6 +1912,12 @@ static int bond_release_all(struct net_device *bond_dev) > slave_dev = slave->dev; > bond_detach_slave(bond, slave); > >+ /* now that the slave is detached, unlock and perform >+ * all the undo steps that should not be called from >+ * within a lock. >+ */ >+ write_unlock_bh(&bond->lock); >+ > if ((bond->params.mode == BOND_MODE_TLB) || > (bond->params.mode == BOND_MODE_ALB)) { > /* must be called only after the slave >@@ -1920,12 +1928,6 @@ static int bond_release_all(struct net_device *bond_dev) > > bond_compute_features(bond); > >- /* now that the slave is detached, unlock and perform >- * all the undo steps that should not be called from >- * within a lock. >- */ >- write_unlock_bh(&bond->lock); >- > bond_destroy_slave_symlinks(bond_dev, slave_dev); > bond_del_vlans_from_slave(bond, slave_dev); > >@@ -2388,7 +2390,9 @@ void bond_mii_monitor(void *work_data) > rtnl_lock(); > read_lock(&bond->lock); > __bond_mii_monitor(bond, 1); >- rtnl_unlock(); >+ read_unlock(&bond->lock); >+ rtnl_unlock(); /* might sleep, hold no other locks */ >+ read_lock(&bond->lock); > } > > delay = ((bond->params.miimon * HZ) / 1000) ? : 1; >@@ -3403,9 +3407,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond > case NETDEV_CHANGENAME: > return bond_event_changename(event_bond); > case NETDEV_UNREGISTER: >- /* >- * TODO: remove a bond from the list? >- */ >+ bond_release_all(event_bond->dev); > break; > default: > break; >@@ -4551,18 +4553,27 @@ static void bond_free_all(void) > > /* > * Convert string input module parms. Accept either the >- * number of the mode or its string name. >+ * number of the mode or its string name. A bit complicated because >+ * some mode names are substrings of other names, and calls from sysfs >+ * may have whitespace in the name (trailing newlines, for example). > */ >-int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) >+int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl) > { >- int i; >+ int mode = -1, i, rv; >+ char modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, }; >+ >+ rv = sscanf(buf, "%d", &mode); >+ if (!rv) { >+ rv = sscanf(buf, "%20s", modestr); >+ if (!rv) >+ return -1; >+ } > > for (i = 0; tbl[i].modename; i++) { >- if ((isdigit(*mode_arg) && >- tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || >- (strcmp(mode_arg, tbl[i].modename) == 0)) { >+ if (mode == tbl[i].mode) >+ return tbl[i].mode; >+ if (strcmp(modestr, tbl[i].modename) == 0) > return tbl[i].mode; >- } > } > > return -1; >@@ -4876,9 +4887,22 @@ static struct lock_class_key bonding_netdev_xmit_lock_key; > int bond_create(char *name, struct bond_params *params, struct bonding **newbond) > { > struct net_device *bond_dev; >+ struct bonding *bond, *nxt; > int res; > > rtnl_lock(); >+ down_write(&bonding_rwsem); >+ >+ /* Check to see if the bond already exists. */ >+ list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) >+ if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { >+ printk(KERN_ERR DRV_NAME >+ ": cannot add bond %s; it already exists\n", >+ name); >+ res = -EPERM; >+ goto out_rtnl; >+ } >+ > bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", > ether_setup); > if (!bond_dev) { >@@ -4919,10 +4943,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond > > netif_carrier_off(bond_dev); > >+ up_write(&bonding_rwsem); > rtnl_unlock(); /* allows sysfs registration of net device */ > res = bond_create_sysfs_entry(bond_dev->priv); > if (res < 0) { > rtnl_lock(); >+ down_write(&bonding_rwsem); > goto out_bond; > } > >@@ -4933,6 +4959,7 @@ out_bond: > out_netdev: > free_netdev(bond_dev); > out_rtnl: >+ up_write(&bonding_rwsem); > rtnl_unlock(); > return res; > } >@@ -4953,6 +4980,9 @@ static int __init bonding_init(void) > #ifdef CONFIG_PROC_FS > bond_create_proc_dir(); > #endif >+ >+ init_rwsem(&bonding_rwsem); >+ > for (i = 0; i < max_bonds; i++) { > res = bond_create(NULL, &bonding_defaults, NULL); > if (res) >diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c >index 51475a1..dbd9b96 100644 >--- a/drivers/net/bonding/bond_sysfs.c >+++ b/drivers/net/bonding/bond_sysfs.c >@@ -110,11 +110,10 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t > { > char command[IFNAMSIZ + 1] = {0, }; > char *ifname; >- int res = count; >+ int rv, res = count; > struct bonding *bond; > struct bonding *nxt; > >- down_write(&(bonding_rwsem)); > sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ > ifname = command + 1; > if ((strlen(command) <= 1) || >@@ -122,39 +121,28 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t > goto err_no_cmd; > > if (command[0] == '+') { >- >- /* Check to see if the bond already exists. */ >- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) >- if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { >- printk(KERN_ERR DRV_NAME >- ": cannot add bond %s; it already exists\n", >- ifname); >- res = -EPERM; >- goto out; >- } >- > printk(KERN_INFO DRV_NAME > ": %s is being created...\n", ifname); >- if (bond_create(ifname, &bonding_defaults, &bond)) { >- printk(KERN_INFO DRV_NAME >- ": %s interface already exists. Bond creation failed.\n", >- ifname); >- res = -EPERM; >+ rv = bond_create(ifname, &bonding_defaults, &bond); >+ if (rv) { >+ printk(KERN_INFO DRV_NAME ": Bond creation failed.\n"); >+ res = rv; > } > goto out; > } > > if (command[0] == '-') { >+ rtnl_lock(); >+ down_write(&bonding_rwsem); >+ > list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) > if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { >- rtnl_lock(); > /* check the ref count on the bond's kobject. > * If it's > expected, then there's a file open, > * and we have to fail. > */ > if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount) > > expected_refcount){ >- rtnl_unlock(); > printk(KERN_INFO DRV_NAME > ": Unable remove bond %s due to open references.\n", > ifname); >@@ -165,6 +153,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t > ": %s is being deleted...\n", > bond->dev->name); > bond_destroy(bond); >+ up_write(&bonding_rwsem); > rtnl_unlock(); > goto out; > } >@@ -172,6 +161,8 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t > printk(KERN_ERR DRV_NAME > ": unable to delete non-existent bond %s\n", ifname); > res = -ENODEV; >+ up_write(&bonding_rwsem); >+ rtnl_unlock(); > goto out; > } > >@@ -184,7 +175,6 @@ err_no_cmd: > * get called forever, which is bad. > */ > out: >- up_write(&(bonding_rwsem)); > return res; > } > /* class attribute for bond_masters file. This ends up in /sys/class/net */ >@@ -270,6 +260,9 @@ static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, > > /* Note: We can't hold bond->lock here, as bond_create grabs it. */ > >+ rtnl_lock(); >+ down_write(&(bonding_rwsem)); >+ > sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ > ifname = command + 1; > if ((strlen(command) <= 1) || >@@ -334,9 +327,7 @@ static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, > dev->mtu = bond->dev->mtu; > } > } >- rtnl_lock(); > res = bond_enslave(bond->dev, dev); >- rtnl_unlock(); > if (res) { > ret = res; > } >@@ -353,12 +344,10 @@ static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, > if (dev) { > printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", > bond->dev->name, dev->name); >- rtnl_lock(); > if (bond->setup_by_slave) > res = bond_release_and_destroy(bond->dev, dev); > else > res = bond_release(bond->dev, dev); >- rtnl_unlock(); > if (res) { > ret = res; > goto out; >@@ -383,6 +372,8 @@ err_no_cmd: > ret = -EPERM; > > out: >+ up_write(&(bonding_rwsem)); >+ rtnl_unlock(); > return ret; > } > >@@ -414,7 +405,7 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size > goto out; > } > >- new_value = bond_parse_parm((char *)buf, bond_mode_tbl); >+ new_value = bond_parse_parm(buf, bond_mode_tbl); > if (new_value < 0) { > printk(KERN_ERR DRV_NAME > ": %s: Ignoring invalid mode value %.*s.\n", >@@ -465,7 +456,7 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, > goto out; > } > >- new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl); >+ new_value = bond_parse_parm(buf, xmit_hashtype_tbl); > if (new_value < 0) { > printk(KERN_ERR DRV_NAME > ": %s: Ignoring invalid xmit hash policy value %.*s.\n", >@@ -501,7 +492,7 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b > int new_value; > struct bonding *bond = to_bond(cd); > >- new_value = bond_parse_parm((char *)buf, arp_validate_tbl); >+ new_value = bond_parse_parm(buf, arp_validate_tbl); > if (new_value < 0) { > printk(KERN_ERR DRV_NAME > ": %s: Ignoring invalid arp_validate value %s\n", >@@ -906,7 +897,7 @@ static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size > goto out; > } > >- new_value = bond_parse_parm((char *)buf, bond_lacp_tbl); >+ new_value = bond_parse_parm(buf, bond_lacp_tbl); > > if ((new_value == 1) || (new_value == 0)) { > bond->params.lacp_fast = new_value; >@@ -1365,8 +1356,6 @@ int bond_create_sysfs(void) > int ret = 0; > struct bonding *firstbond; > >- init_rwsem(&bonding_rwsem); >- > /* get the netdev class pointer */ > firstbond = container_of(bond_dev_list.next, struct bonding, bond_list); > if (!firstbond) >diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h >index aa27cbd..aab73ec 100644 >--- a/drivers/net/bonding/bonding.h >+++ b/drivers/net/bonding/bonding.h >@@ -141,6 +141,8 @@ struct bond_parm_tbl { > int mode; > }; > >+#define BOND_MAX_MODENAME_LEN 20 >+ > struct vlan_entry { > struct list_head vlan_list; > __be32 vlan_ip; >@@ -313,7 +315,7 @@ void bond_mii_monitor(void *); > void bond_loadbalance_arp_mon(void *); > void bond_activebackup_arp_mon(void *); > void bond_set_mode_ops(struct bonding *bond, int mode); >-int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl); >+int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl); > void bond_select_active_slave(struct bonding *bond); > void bond_change_active_slave(struct bonding *bond, struct slave *new_active); > void bond_register_arp(struct bonding *);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 268001
:
181361
| 292974