Page MenuHomeFreeBSD

ifnet: Fix the teardown process of an interface
Needs ReviewPublic

Authored by zlei on Fri, Mar 14, 12:01 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Mar 18, 11:42 AM
Unknown Object (File)
Tue, Mar 18, 9:24 AM
Unknown Object (File)
Mon, Mar 17, 1:39 AM
Unknown Object (File)
Sun, Mar 16, 6:18 AM
Unknown Object (File)
Sun, Mar 16, 4:17 AM
Unknown Object (File)
Sun, Mar 16, 3:41 AM
Unknown Object (File)
Fri, Mar 14, 6:57 PM
Subscribers

Details

Summary

The interface should be brought down before it been detached, but lots
of drivers do not. Ideally this should be done on the driver side, but
that requires lots of modification so let's do the job in if_detach_internal().

PR: 279653
PR: 285129
MFC after: 2 weeks

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

zlei requested review of this revision.Fri, Mar 14, 12:01 PM

This is only the partial fix. I'm cleaning up the NET_EPOCH_ENTER / NET_EPOCH_EXIT and trying to find out all possible the races.

Typically the input / output paths should have

NET_EPOCH_ENTER
...
NET_EPOCH_EXIT
...

NET_EPOCH_ENTER
if ((ifp->if_flags & IFF_UP) == 0)
    abort processing

NET_EPOCH_EXIT

Do you have a stress test suite you use for testing these changes?

I'll do a CFT on this change with OPNsense users next week. A few can trigger the if_afdata panics with PPPoE.

Why exactly does this fix the problem? As I understand, the specific bug is (probably) that NET_EPOCH_WAIT() is used too early. At that point, the ifnet is still visible from several global data structures, and in particular the routing tables, since rt_flushifroutes() is not called yet. From what I can see, clearing IFF_UP does not seem to be sufficient. Maybe some drivers set their link state to down when stopped, but is it guaranteed?

sys/net/if.c
1137

I'd explain a bit further that this ensures that the driver sees that IFF_UP is clear.

1139

Should we zero the structure here, just in case drivers peek at other fields besides ifr.ifr_flags and ifr.ifr_flagshigh?

Do you have a stress test suite you use for testing these changes?

I have one Dtrace script and a script for the input path, ether_input_internal() / ip6_input() and can reliable crash the kernel.

There're other crashing paths. Still trying to figure out them all.

Why exactly does this fix the problem? As I understand, the specific bug is (probably) that NET_EPOCH_WAIT() is used too early.

Yes. This is only part of the fix. Still working on it yet. Found other paths to crash to kernel.

At that point, the ifnet is still visible from several global data structures, and in particular the routing tables, since rt_flushifroutes() is not called yet. From what I can see, clearing IFF_UP does not seem to be sufficient. Maybe some drivers set their link state to down when stopped, but is it guaranteed?

Yes, you're right. While reviewing the logic teardown and the netisr part, I can conclude that merely clearing IFF_UP is not sufficient. This only fix one path, that is ether_input_internal() / ip6_input().

Well I though that it is the best result that the system panics when hitting this bug, but I was wrong.

The test shows it is even possible to write freed memory. That is,
thread A,

			(*dp->dom_ifdetach)(ifp,
			    ifp->if_afdata[dp->dom_family]);
			ifp->if_afdata[dp->dom_family] = NULL;

but thread B see stall reference, i.e. ifp->if_afdata[dp->dom_family] != NULL.

For 285129 this still crashes in the same place: https://github.com/opnsense/src/issues/207#issuecomment-2733080313

Is that based on stable/14 ?

Correct. Am I missing patches for this to make more sense?

For 285129 this still crashes in the same place: https://github.com/opnsense/src/issues/207#issuecomment-2733080313

Is that based on stable/14 ?

Correct. Am I missing patches for this to make more sense?

No, this is not complete, but your feedback is useful.

The logic of if_vmove() of stable/13 is a little different from stable/14, and I'm not testing on stable/13 yet. Just asked to confirm.