Skip to content

Commit

Permalink
bonding: fix multiple 3ad mode sysfs race conditions
Browse files Browse the repository at this point in the history
When bond_3ad_get_active_agg_info() is used in all show_ad_ functions
it is not protected against slave manipulation and since it walks over
the slaves and uses them, this can easily result in NULL pointer
dereference or use of freed memory. Both the new wrapper and the
internal function are exported to the bonding as they're needed in
different places.

Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
nikolay@redhat.com authored and David S. Miller committed May 20, 2013
1 parent 5a5c5fd commit 318debd
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 10 deletions.
21 changes: 17 additions & 4 deletions drivers/net/bonding/bond_3ad.c
Original file line number Diff line number Diff line change
Expand Up @@ -2360,14 +2360,15 @@ int bond_3ad_set_carrier(struct bonding *bond)
}

/**
* bond_3ad_get_active_agg_info - get information of the active aggregator
* __bond_3ad_get_active_agg_info - get information of the active aggregator
* @bond: bonding struct to work on
* @ad_info: ad_info struct to fill with the bond's info
*
* Returns: 0 on success
* < 0 on error
*/
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
int __bond_3ad_get_active_agg_info(struct bonding *bond,
struct ad_info *ad_info)
{
struct aggregator *aggregator = NULL;
struct port *port;
Expand All @@ -2391,6 +2392,18 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
return -1;
}

/* Wrapper used to hold bond->lock so no slave manipulation can occur */
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
{
int ret;

read_lock(&bond->lock);
ret = __bond_3ad_get_active_agg_info(bond, ad_info);
read_unlock(&bond->lock);

return ret;
}

int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
{
struct slave *slave, *start_at;
Expand All @@ -2402,8 +2415,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
struct ad_info ad_info;
int res = 1;

if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n",
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
dev->name);
goto out;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/bonding/bond_3ad.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave);
void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
int __bond_3ad_get_active_agg_info(struct bonding *bond,
struct ad_info *ad_info);
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/bonding/bond_procfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
ad_select_tbl[bond->params.ad_select].modename);

if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
seq_printf(seq, "bond %s has no active aggregator\n",
bond->dev->name);
} else {
Expand Down
9 changes: 4 additions & 5 deletions drivers/net/bonding/bond_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1319,7 +1319,6 @@ static ssize_t bonding_show_mii_status(struct device *d,
}
static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);


/*
* Show current 802.3ad aggregator ID.
*/
Expand All @@ -1333,7 +1332,7 @@ static ssize_t bonding_show_ad_aggregator(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
(bond_3ad_get_active_agg_info(bond, &ad_info))
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.aggregator_id);
}

Expand All @@ -1355,7 +1354,7 @@ static ssize_t bonding_show_ad_num_ports(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
(bond_3ad_get_active_agg_info(bond, &ad_info))
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.ports);
}

Expand All @@ -1377,7 +1376,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
(bond_3ad_get_active_agg_info(bond, &ad_info))
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.actor_key);
}

Expand All @@ -1399,7 +1398,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
(bond_3ad_get_active_agg_info(bond, &ad_info))
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.partner_key);
}

Expand Down

0 comments on commit 318debd

Please sign in to comment.