From: Jamie Iles <jamie@nuviainc.com>
To: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jamie Iles <jamie@nuviainc.com>,
netdev@vger.kernel.org, Qiushi Wu <wu000273@umn.edu>,
Jay Vosburgh <j.vosburgh@gmail.com>,
Veaceslav Falico <vfalico@gmail.com>,
Andy Gospodarek <andy@greyhouse.net>
Subject: Re: [RESEND PATCH] bonding: wait for sysfs kobject destruction before freeing struct slave
Date: Thu, 5 Nov 2020 18:11:08 +0000 [thread overview]
Message-ID: <20201105181108.GA2360@poplar> (raw)
In-Reply-To: <89416a2d-8a9b-f225-3c2a-16210df25e61@gmail.com>
Hi Eric,
On Thu, Nov 05, 2020 at 01:49:03PM +0100, Eric Dumazet wrote:
> On 11/5/20 9:41 AM, Jamie Iles wrote:
> > syzkaller found that with CONFIG_DEBUG_KOBJECT_RELEASE=y, releasing a
> > struct slave device could result in the following splat:
> >
> >
>
> > This is a potential use-after-free if the sysfs nodes are being accessed
> > whilst removing the struct slave, so wait for the object destruction to
> > complete before freeing the struct slave itself.
> >
> > Fixes: 07699f9a7c8d ("bonding: add sysfs /slave dir for bond slave devices.")
> > Fixes: a068aab42258 ("bonding: Fix reference count leak in bond_sysfs_slave_add.")
> > Cc: Qiushi Wu <wu000273@umn.edu>
> > Cc: Jay Vosburgh <j.vosburgh@gmail.com>
> > Cc: Veaceslav Falico <vfalico@gmail.com>
> > Cc: Andy Gospodarek <andy@greyhouse.net>
> > Signed-off-by: Jamie Iles <jamie@nuviainc.com>
> > ---
...
> This seems weird, are we going to wait for a completion while RTNL is held ?
> I am pretty sure this could be exploited by malicious user/syzbot.
>
> The .release() handler could instead perform a refcounted
> bond_free_slave() action.
Okay, so were you thinking along the lines of this moving the lifetime
of the slave to the kobject?
Thanks,
Jamie
diff --git i/drivers/net/bonding/bond_main.c w/drivers/net/bonding/bond_main.c
index 84ecbc6fa0ff..ea8ecc6e87c2 100644
--- i/drivers/net/bonding/bond_main.c
+++ w/drivers/net/bonding/bond_main.c
@@ -1481,7 +1481,7 @@ static struct slave *bond_alloc_slave(struct bonding *bond)
return slave;
}
-static void bond_free_slave(struct slave *slave)
+void bond_free_slave(struct slave *slave)
{
struct bonding *bond = bond_get_bond_by_slave(slave);
@@ -1691,6 +1691,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
*/
new_slave->queue_id = 0;
+ res = bond_slave_kobj_init(new_slave);
+ if (res)
+ goto err_free;
+
/* Save slave's original mtu and then set it to match the bond */
new_slave->original_mtu = slave_dev->mtu;
res = dev_set_mtu(slave_dev, bond->dev->mtu);
@@ -1912,7 +1916,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
if (bond_dev->flags & IFF_PROMISC) {
res = dev_set_promiscuity(slave_dev, 1);
if (res)
- goto err_sysfs_del;
+ goto err_upper_unlink;
}
/* set allmulti level to new slave */
@@ -1921,7 +1925,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
if (res) {
if (bond_dev->flags & IFF_PROMISC)
dev_set_promiscuity(slave_dev, -1);
- goto err_sysfs_del;
+ goto err_upper_unlink;
}
}
@@ -1961,9 +1965,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
return 0;
/* Undo stages on error */
-err_sysfs_del:
- bond_sysfs_slave_del(new_slave);
-
err_upper_unlink:
bond_upper_dev_unlink(bond, new_slave);
@@ -2007,7 +2008,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
dev_set_mtu(slave_dev, new_slave->original_mtu);
err_free:
- bond_free_slave(new_slave);
+ bond_slave_kobj_put(new_slave);
err_undo_flags:
/* Enslave of first slave has failed and we need to fix master's mac */
@@ -2066,8 +2067,6 @@ static int __bond_release_one(struct net_device *bond_dev,
bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW);
- bond_sysfs_slave_del(slave);
-
/* recompute stats just before removing the slave */
bond_get_stats(bond->dev, &bond->bond_stats);
@@ -2187,7 +2186,7 @@ static int __bond_release_one(struct net_device *bond_dev,
if (!netif_is_bond_master(slave_dev))
slave_dev->priv_flags &= ~IFF_BONDING;
- bond_free_slave(slave);
+ bond_slave_kobj_put(slave);
return 0;
}
diff --git i/drivers/net/bonding/bond_sysfs_slave.c w/drivers/net/bonding/bond_sysfs_slave.c
index 9b8346638f69..67732078ef26 100644
--- i/drivers/net/bonding/bond_sysfs_slave.c
+++ w/drivers/net/bonding/bond_sysfs_slave.c
@@ -136,24 +136,35 @@ static const struct sysfs_ops slave_sysfs_ops = {
.show = slave_show,
};
+static void slave_release(struct kobject *kobj)
+{
+ struct slave *slave = to_slave(kobj);
+
+ bond_free_slave(slave);
+}
+
static struct kobj_type slave_ktype = {
+ .release = slave_release,
#ifdef CONFIG_SYSFS
.sysfs_ops = &slave_sysfs_ops,
#endif
};
+int bond_slave_kobj_init(struct slave *slave)
+{
+ int err = kobject_init_and_add(&slave->kobj, &slave_ktype,
+ &(slave->dev->dev.kobj), "bonding_slave");
+ if (err)
+ kobject_put(&slave->kobj);
+
+ return err;
+}
+
int bond_sysfs_slave_add(struct slave *slave)
{
const struct slave_attribute **a;
int err;
- err = kobject_init_and_add(&slave->kobj, &slave_ktype,
- &(slave->dev->dev.kobj), "bonding_slave");
- if (err) {
- kobject_put(&slave->kobj);
- return err;
- }
-
for (a = slave_attrs; *a; ++a) {
err = sysfs_create_file(&slave->kobj, &((*a)->attr));
if (err) {
@@ -165,7 +176,7 @@ int bond_sysfs_slave_add(struct slave *slave)
return 0;
}
-void bond_sysfs_slave_del(struct slave *slave)
+void bond_slave_kobj_put(struct slave *slave)
{
const struct slave_attribute **a;
diff --git i/include/net/bonding.h w/include/net/bonding.h
index 7d132cc1e584..ccb07e3e495e 100644
--- i/include/net/bonding.h
+++ w/include/net/bonding.h
@@ -622,10 +622,12 @@ int bond_create(struct net *net, const char *name);
int bond_create_sysfs(struct bond_net *net);
void bond_destroy_sysfs(struct bond_net *net);
void bond_prepare_sysfs_group(struct bonding *bond);
+int bond_slave_kobj_init(struct slave *slave);
int bond_sysfs_slave_add(struct slave *slave);
-void bond_sysfs_slave_del(struct slave *slave);
+void bond_slave_kobj_put(struct slave *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
struct netlink_ext_ack *extack);
+void bond_free_slave(struct slave *slave);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb);
int bond_set_carrier(struct bonding *bond);
next prev parent reply other threads:[~2020-11-05 18:11 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-05 8:41 [RESEND PATCH] bonding: wait for sysfs kobject destruction before freeing struct slave Jamie Iles
2020-11-05 12:49 ` Eric Dumazet
2020-11-05 18:11 ` Jamie Iles [this message]
2020-11-06 16:17 ` Eric Dumazet
2020-11-13 17:12 ` [PATCHv2] " Jamie Iles
2020-11-17 20:34 ` Jakub Kicinski
2020-11-18 7:58 ` Greg Kroah-Hartman
2020-11-20 14:28 ` [PATCHv3] " Jamie Iles
2020-11-20 15:39 ` Greg Kroah-Hartman
2020-11-21 21:09 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201105181108.GA2360@poplar \
--to=jamie@nuviainc.com \
--cc=andy@greyhouse.net \
--cc=eric.dumazet@gmail.com \
--cc=j.vosburgh@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=vfalico@gmail.com \
--cc=wu000273@umn.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.