* [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR @ 2007-02-18 21:43 Oleg Nesterov 2007-02-19 11:00 ` Jarek Poplawski 2007-02-19 11:27 ` David Howells 0 siblings, 2 replies; 15+ messages in thread From: Oleg Nesterov @ 2007-02-18 21:43 UTC (permalink / raw) To: Andrew Morton, Jarek Poplawski, David S. Miller Cc: David Howells, linux-kernel Afaics, noautorel work_struct buys nothing for "struct net_bridge_port". If del_nbp()->cancel_delayed_work(&p->carrier_check) fails, port_carrier_check may be called later anyway. So the reading of *work in port_carrier_check() is equally unsafe with or without this patch. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> --- WQ/net/bridge/br_if.c~1_bridge 2007-02-18 22:56:49.000000000 +0300 +++ WQ/net/bridge/br_if.c 2007-02-18 23:06:15.000000000 +0300 @@ -85,7 +85,6 @@ static void port_carrier_check(struct wo dev = container_of(work, struct net_bridge_port, carrier_check.work)->dev; - work_release(work); rtnl_lock(); p = dev->br_port; @@ -282,7 +281,7 @@ static struct net_bridge_port *new_nbp(s p->port_no = index; br_init_port(p); p->state = BR_STATE_DISABLED; - INIT_DELAYED_WORK_NAR(&p->carrier_check, port_carrier_check); + INIT_DELAYED_WORK(&p->carrier_check, port_carrier_check); br_stp_port_timer_init(p); kobject_init(&p->kobj); ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-18 21:43 [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR Oleg Nesterov @ 2007-02-19 11:00 ` Jarek Poplawski 2007-02-19 12:03 ` Oleg Nesterov 2007-02-19 11:27 ` David Howells 1 sibling, 1 reply; 15+ messages in thread From: Jarek Poplawski @ 2007-02-19 11:00 UTC (permalink / raw) To: Oleg Nesterov; +Cc: Andrew Morton, David S. Miller, David Howells, linux-kernel On Mon, Feb 19, 2007 at 12:43:59AM +0300, Oleg Nesterov wrote: > Afaics, noautorel work_struct buys nothing for "struct net_bridge_port". > > If del_nbp()->cancel_delayed_work(&p->carrier_check) fails, port_carrier_check > may be called later anyway. So the reading of *work in port_carrier_check() is > equally unsafe with or without this patch. I think this _WORK_NAR is to give some additional control, but also is more logical: it lets to decide when the work_struct is really release-able (and it's definitely not before work function is called, as without noautorel). So, even if this functionality isn't used now, I can't see what changing this could buy. Regards, Jarek P. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 11:00 ` Jarek Poplawski @ 2007-02-19 12:03 ` Oleg Nesterov 2007-02-19 13:27 ` Jarek Poplawski 0 siblings, 1 reply; 15+ messages in thread From: Oleg Nesterov @ 2007-02-19 12:03 UTC (permalink / raw) To: Jarek Poplawski Cc: Andrew Morton, David S. Miller, David Howells, linux-kernel On 02/19, Jarek Poplawski wrote: > > On Mon, Feb 19, 2007 at 12:43:59AM +0300, Oleg Nesterov wrote: > > Afaics, noautorel work_struct buys nothing for "struct net_bridge_port". > > > > If del_nbp()->cancel_delayed_work(&p->carrier_check) fails, port_carrier_check > > may be called later anyway. So the reading of *work in port_carrier_check() is > > equally unsafe with or without this patch. > > I think this _WORK_NAR is to give some additional > control, but also is more logical: it lets to decide > when the work_struct is really release-able Sadly, it doesn't help here. (and it's > definitely not before work function is called, as > without noautorel). kfree() doesn't check WORK_STRUCT_PENDING, it makes no difference if it is set or not when work->func() runs. > So, even if this functionality isn't used now, I can't > see what changing this could buy. We are going to kill _NAR stuff. Oleg. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 12:03 ` Oleg Nesterov @ 2007-02-19 13:27 ` Jarek Poplawski 2007-02-19 15:04 ` Oleg Nesterov 0 siblings, 1 reply; 15+ messages in thread From: Jarek Poplawski @ 2007-02-19 13:27 UTC (permalink / raw) To: Oleg Nesterov; +Cc: Andrew Morton, David S. Miller, David Howells, linux-kernel On Mon, Feb 19, 2007 at 03:03:53PM +0300, Oleg Nesterov wrote: > On 02/19, Jarek Poplawski wrote: ... > kfree() doesn't check WORK_STRUCT_PENDING, it makes no > difference if it is set or not when work->func() runs. It looks like it's to be checked before kfree. > > So, even if this functionality isn't used now, I can't > > see what changing this could buy. > > We are going to kill _NAR stuff. If you're sure nobody uses this in any way then it seems the right decision. Jarek P. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 13:27 ` Jarek Poplawski @ 2007-02-19 15:04 ` Oleg Nesterov 2007-02-20 13:25 ` Jarek Poplawski 0 siblings, 1 reply; 15+ messages in thread From: Oleg Nesterov @ 2007-02-19 15:04 UTC (permalink / raw) To: Jarek Poplawski Cc: Andrew Morton, David S. Miller, David Howells, linux-kernel On 02/19, Jarek Poplawski wrote: > > On Mon, Feb 19, 2007 at 03:03:53PM +0300, Oleg Nesterov wrote: > > On 02/19, Jarek Poplawski wrote: > ... > > kfree() doesn't check WORK_STRUCT_PENDING, it makes no > > difference if it is set or not when work->func() runs. > > It looks like it's to be checked before kfree. Here, br_add_if: schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); schedule_delayed_work() fails if this bit is set. So the only difference with this patch is: before: schedule_delayed_work() fails unless port_carrier_check() passed work_release() (before rtnl_lock()) after: schedule_delayed_work() fails unless run_workqueue() cleared this bit (before calling port_carrier_check()) > > We are going to kill _NAR stuff. > > If you're sure nobody uses this in any way then it > seems the right decision. Yes, this series converts all users. Oleg. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 15:04 ` Oleg Nesterov @ 2007-02-20 13:25 ` Jarek Poplawski 2007-02-20 14:25 ` Oleg Nesterov 0 siblings, 1 reply; 15+ messages in thread From: Jarek Poplawski @ 2007-02-20 13:25 UTC (permalink / raw) To: Oleg Nesterov; +Cc: Andrew Morton, David S. Miller, David Howells, linux-kernel On Mon, Feb 19, 2007 at 06:04:45PM +0300, Oleg Nesterov wrote: > On 02/19, Jarek Poplawski wrote: > > > > On Mon, Feb 19, 2007 at 03:03:53PM +0300, Oleg Nesterov wrote: > > > On 02/19, Jarek Poplawski wrote: > > ... > > > kfree() doesn't check WORK_STRUCT_PENDING, it makes no > > > difference if it is set or not when work->func() runs. > > > > It looks like it's to be checked before kfree. > > Here, > br_add_if: ... I meant "it's to be checked", if it's used by a program. The name: work_release seems to tell the work function could signal, when it doesn't need a structure no more. But br_if.c doesn't seem to use this infomation now, so there should be no difference after changing to "without _NAR". This change will limit some potential changes in the future, but if it's not used by anybody than the simpler api is a gain. Jarek P. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-20 13:25 ` Jarek Poplawski @ 2007-02-20 14:25 ` Oleg Nesterov 0 siblings, 0 replies; 15+ messages in thread From: Oleg Nesterov @ 2007-02-20 14:25 UTC (permalink / raw) To: Jarek Poplawski Cc: Andrew Morton, David S. Miller, David Howells, linux-kernel On 02/20, Jarek Poplawski wrote: > > On Mon, Feb 19, 2007 at 06:04:45PM +0300, Oleg Nesterov wrote: > > On 02/19, Jarek Poplawski wrote: > > > > > > It looks like it's to be checked before kfree. > > > > Here, > > br_add_if: > ... > > I meant "it's to be checked", Jarek, I was too quick and misread your message, sorry! > if it's used by a program. > The name: work_release seems to tell the work function > could signal, when it doesn't need a structure no more. > But br_if.c doesn't seem to use this infomation now, > so there should be no difference after changing to > "without _NAR". This change will limit some potential > changes in the future, but if it's not used by anybody > than the simpler api is a gain. Agreed. Oleg. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-18 21:43 [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR Oleg Nesterov 2007-02-19 11:00 ` Jarek Poplawski @ 2007-02-19 11:27 ` David Howells 2007-02-19 11:59 ` Oleg Nesterov 1 sibling, 1 reply; 15+ messages in thread From: David Howells @ 2007-02-19 11:27 UTC (permalink / raw) To: Oleg Nesterov Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel Oleg Nesterov <oleg@tv-sign.ru> wrote: > Afaics, noautorel work_struct buys nothing for "struct net_bridge_port". You may be right. > If del_nbp()->cancel_delayed_work(&p->carrier_check) fails, port_carrier_check > may be called later anyway. Called by what? Something outside of br_if.c? > So the reading of *work in port_carrier_check() is equally unsafe with or > without this patch. Hmmm... cancel_delayed_work() in del_nbp() probably ought to be followed by a flush_scheduled_work(). David ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 11:27 ` David Howells @ 2007-02-19 11:59 ` Oleg Nesterov 2007-02-19 13:15 ` David Howells 2007-02-19 22:11 ` PATCH? net/bridge/br_if.c: fix use after free in port_carrier_check() Oleg Nesterov 0 siblings, 2 replies; 15+ messages in thread From: Oleg Nesterov @ 2007-02-19 11:59 UTC (permalink / raw) To: David Howells Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel On 02/19, David Howells wrote: > > Oleg Nesterov <oleg@tv-sign.ru> wrote: > > > Afaics, noautorel work_struct buys nothing for "struct net_bridge_port". > > You may be right. > > > If del_nbp()->cancel_delayed_work(&p->carrier_check) fails, port_carrier_check > > may be called later anyway. > > Called by what? Something outside of br_if.c? No. if cancel_delayed_work() fails, the work may sit pending in cwq->worklist, or it may be running right now, waiting for rtnl_mutex. > > So the reading of *work in port_carrier_check() is equally unsafe with or > > without this patch. > > Hmmm... cancel_delayed_work() in del_nbp() probably ought to be followed by a > flush_scheduled_work(). Yes, but this deadlocks: we hold rtnl_mutex, and work->func() takes it too. I think the fix should be so that port_carrier_check() does get/put on "struct net_bridge_port" (container), but not on "struct net_device", and del_nbp(struct net_bridge_port *p) if (cancel_delayed_work(&p->carrier_check)) - dev_put(p->dev); + kobject_put(&p->kobj); Oleg. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 11:59 ` Oleg Nesterov @ 2007-02-19 13:15 ` David Howells 2007-02-19 14:56 ` Oleg Nesterov 2007-02-19 22:11 ` PATCH? net/bridge/br_if.c: fix use after free in port_carrier_check() Oleg Nesterov 1 sibling, 1 reply; 15+ messages in thread From: David Howells @ 2007-02-19 13:15 UTC (permalink / raw) To: Oleg Nesterov Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel Oleg Nesterov <oleg@tv-sign.ru> wrote: > > Called by what? Something outside of br_if.c? > > No. if cancel_delayed_work() fails, the work may sit pending in cwq->worklist, > or it may be running right now, waiting for rtnl_mutex. OIC. I understood "called" to mean "scheduled", but that's not what you meant. > > Hmmm... cancel_delayed_work() in del_nbp() probably ought to be followed by > > a flush_scheduled_work(). > > Yes, but this deadlocks: we hold rtnl_mutex, and work->func() takes it too. Oh, yuck! Hmmm... You've got a work_struct (well, a delayed_work actually) - can you just punt the destruction of the object over to keventd to perform, I wonder? The big problem with that that I see is that the workqueue facility has no guards in place against a work_struct's handler function running on several CPUs at once in response to the same work_struct. > I think the fix should be so that port_carrier_check() does get/put on > "struct net_bridge_port" (container), but not on "struct net_device", and I'm not sure how this helps. You still have to get rid of the net_device at some point. David ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 13:15 ` David Howells @ 2007-02-19 14:56 ` Oleg Nesterov 2007-02-19 15:15 ` David Howells 0 siblings, 1 reply; 15+ messages in thread From: Oleg Nesterov @ 2007-02-19 14:56 UTC (permalink / raw) To: David Howells Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel On 02/19, David Howells wrote: > > Hmmm... You've got a work_struct (well, a delayed_work actually) - can you > just punt the destruction of the object over to keventd to perform, I wonder? Yes, this is close (I think) to what I suggested, see below, > The big problem with that that I see is that the workqueue facility has no > guards in place against a work_struct's handler function running on several > CPUs at once in response to the same work_struct. Yes. And for this problem WORK_STRUCT_NOAUTOREL does help, but not so much. It can prevent re-scheduling of the same work, but only if work->func() did not do work_release() yet. > > I think the fix should be so that port_carrier_check() does get/put on > > "struct net_bridge_port" (container), but not on "struct net_device", and > > I'm not sure how this helps. You still have to get rid of the net_device at > some point. Yes, destroy_nbp() does dev_put(dev). del_nbp() sets dev->br_port = NULL, port_carrier_check() goes to "done" in that case. So everething looks safe to me (but again, I do not even know what the "bridge" is :), so we should only take care about container, nothing more. I'll try to make a patch for illustration on evening. Oleg. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR 2007-02-19 14:56 ` Oleg Nesterov @ 2007-02-19 15:15 ` David Howells 0 siblings, 0 replies; 15+ messages in thread From: David Howells @ 2007-02-19 15:15 UTC (permalink / raw) To: Oleg Nesterov Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel Oleg Nesterov <oleg@tv-sign.ru> wrote: > Yes, destroy_nbp() does dev_put(dev). del_nbp() sets dev->br_port = NULL, > port_carrier_check() goes to "done" in that case. So everething looks safe > to me (but again, I do not even know what the "bridge" is :), so we should > only take care about container, nothing more. Sounds like a plan. > I'll try to make a patch for illustration on evening. :-) David ^ permalink raw reply [flat|nested] 15+ messages in thread
* PATCH? net/bridge/br_if.c: fix use after free in port_carrier_check() 2007-02-19 11:59 ` Oleg Nesterov 2007-02-19 13:15 ` David Howells @ 2007-02-19 22:11 ` Oleg Nesterov 2007-02-20 10:44 ` David Howells 1 sibling, 1 reply; 15+ messages in thread From: Oleg Nesterov @ 2007-02-19 22:11 UTC (permalink / raw) To: David Howells Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel On 02/19, Oleg Nesterov wrote: > > I think the fix should be so that port_carrier_check() does get/put on > "struct net_bridge_port" (container), but not on "struct net_device", and > > del_nbp(struct net_bridge_port *p) > > if (cancel_delayed_work(&p->carrier_check)) > - dev_put(p->dev); > + kobject_put(&p->kobj); Perhaps something like the patch below? (on top of this patch). We should do something, the stable tree has the same bug. Oleg. --- WQ/net/bridge/br_if.c~5_bridge_uaf 2007-02-18 23:06:15.000000000 +0300 +++ WQ/net/bridge/br_if.c 2007-02-20 00:59:54.000000000 +0300 @@ -83,14 +83,14 @@ static void port_carrier_check(struct wo struct net_device *dev; struct net_bridge *br; - dev = container_of(work, struct net_bridge_port, - carrier_check.work)->dev; + p = container_of(work, struct net_bridge_port, carrier_check.work); rtnl_lock(); - p = dev->br_port; - if (!p) - goto done; br = p->br; + dev = p->dev; + + if (!dev->br_port) + goto done; if (netif_carrier_ok(dev)) p->path_cost = port_cost(dev); @@ -107,14 +107,16 @@ static void port_carrier_check(struct wo spin_unlock_bh(&br->lock); } done: - dev_put(dev); rtnl_unlock(); + kobject_put(&p->kobj); } static void release_nbp(struct kobject *kobj) { struct net_bridge_port *p = container_of(kobj, struct net_bridge_port, kobj); + + dev_put(p->dev); kfree(p); } @@ -127,12 +129,6 @@ static struct kobj_type brport_ktype = { static void destroy_nbp(struct net_bridge_port *p) { - struct net_device *dev = p->dev; - - p->br = NULL; - p->dev = NULL; - dev_put(dev); - kobject_put(&p->kobj); } @@ -162,7 +158,7 @@ static void del_nbp(struct net_bridge_po dev_set_promiscuity(dev, -1); if (cancel_delayed_work(&p->carrier_check)) - dev_put(dev); + kobject_put(&p->kobj); spin_lock_bh(&br->lock); br_stp_disable_port(p); @@ -446,7 +442,7 @@ int br_add_if(struct net_bridge *br, str br_stp_recalculate_bridge_id(br); br_features_recompute(br); if (schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE)) - dev_hold(dev); + kobject_get(&p->kobj); spin_unlock_bh(&br->lock); ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: PATCH? net/bridge/br_if.c: fix use after free in port_carrier_check() 2007-02-19 22:11 ` PATCH? net/bridge/br_if.c: fix use after free in port_carrier_check() Oleg Nesterov @ 2007-02-20 10:44 ` David Howells 2007-02-20 14:34 ` Oleg Nesterov 0 siblings, 1 reply; 15+ messages in thread From: David Howells @ 2007-02-20 10:44 UTC (permalink / raw) To: Oleg Nesterov Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel Oleg Nesterov <oleg@tv-sign.ru> wrote: > static void release_nbp(struct kobject *kobj) > { > struct net_bridge_port *p > = container_of(kobj, struct net_bridge_port, kobj); > + > + dev_put(p->dev); Does this need to be done with the mutex held? And does anything actually pay attention to the refcount on dev? I assume not... Should you clear p->dev->br_port before calling dev_put()? Looks reasonable. I like it. Acked-By: David Howells <dhowells@redhat.com> ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: PATCH? net/bridge/br_if.c: fix use after free in port_carrier_check() 2007-02-20 10:44 ` David Howells @ 2007-02-20 14:34 ` Oleg Nesterov 0 siblings, 0 replies; 15+ messages in thread From: Oleg Nesterov @ 2007-02-20 14:34 UTC (permalink / raw) To: David Howells Cc: Andrew Morton, Jarek Poplawski, David S. Miller, linux-kernel On 02/20, David Howells wrote: > > Oleg Nesterov <oleg@tv-sign.ru> wrote: > > > static void release_nbp(struct kobject *kobj) > > { > > struct net_bridge_port *p > > = container_of(kobj, struct net_bridge_port, kobj); > > + > > + dev_put(p->dev); > > Does this need to be done with the mutex held? I think no. At least the current code does dev_put() without mutex held. > And does anything actually pay > attention to the refcount on dev? I assume not... I guess net/core/dev.c:netdev_wait_allrefs(), but not sure. > Should you clear p->dev->br_port before calling dev_put()? Looks like it is protected by RCU... Anyway the current code does the same. > Looks reasonable. I like it. > > Acked-By: David Howells <dhowells@redhat.com> Thanks! I'll re-send with a proper changelog later today. Oleg. ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2007-02-20 14:34 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-02-18 21:43 [PATCH 1/3] net/bridge/br_if.c: don't use _WORK_NAR Oleg Nesterov 2007-02-19 11:00 ` Jarek Poplawski 2007-02-19 12:03 ` Oleg Nesterov 2007-02-19 13:27 ` Jarek Poplawski 2007-02-19 15:04 ` Oleg Nesterov 2007-02-20 13:25 ` Jarek Poplawski 2007-02-20 14:25 ` Oleg Nesterov 2007-02-19 11:27 ` David Howells 2007-02-19 11:59 ` Oleg Nesterov 2007-02-19 13:15 ` David Howells 2007-02-19 14:56 ` Oleg Nesterov 2007-02-19 15:15 ` David Howells 2007-02-19 22:11 ` PATCH? net/bridge/br_if.c: fix use after free in port_carrier_check() Oleg Nesterov 2007-02-20 10:44 ` David Howells 2007-02-20 14:34 ` Oleg Nesterov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox