Page MenuHomeFreeBSD

sound: Fix lock order reversals in mseq_open()
ClosedPublic

Authored by christos on Jun 28 2024, 4:19 PM.
Tags
None
Referenced Files
F93166400: D45770.id140632.diff
Sat, Sep 7, 7:44 PM
Unknown Object (File)
Sun, Sep 1, 2:23 AM
Unknown Object (File)
Thu, Aug 29, 3:06 PM
Unknown Object (File)
Fri, Aug 23, 6:58 AM
Unknown Object (File)
Thu, Aug 22, 2:56 PM
Unknown Object (File)
Thu, Aug 22, 2:47 AM
Unknown Object (File)
Wed, Aug 21, 5:28 PM
Unknown Object (File)
Fri, Aug 9, 6:20 AM
Subscribers

Details

Summary

Opening /dev/sequencer after a clean reboot yields:

lock order reversal: (sleepable after non-sleepable)
1st 0xfffffe004a2c2c08 seqflq (seqflq, sleep mutex) @ /mnt/src/sys/dev/sound/midi/sequencer.c:754
2nd 0xffffffff84197ed8 midistat lock (midistat lock, sx) @ /mnt/src/sys/dev/sound/midi/midi.c:1478
lock order seqflq -> midistat lock attempted at:
0xffffffff811c9029 at witness_checkorder+0x12b9
0xffffffff810f18a7 at _sx_xlock+0xf7
0xffffffff8417f992 at midimapper_open+0x22
0xffffffff84182770 at mseq_open+0xf0
0xffffffff80e3380f at devfs_open+0x30f
0xffffffff81b8b4b7 at VOP_OPEN_APV+0x57
0xffffffff812da1e7 at vn_open_vnode+0x397
0xffffffff812d96b3 at vn_open_cred+0xb23
0xffffffff812c2c6b at openatfp+0x52b
0xffffffff812c2711 at sys_openat+0x81
0xffffffff84110579 at filemon_wrapper_openat+0x19
0xffffffff81a223ae at amd64_syscall+0x39e
0xffffffff819dd0eb at fast_syscall_common+0xf8

Expose midistat_lock to midi/midi.c so that we can acquire the lock from
mseq_open() before we lock seq_lock, and introduce _locked variants of
midimapper_open() and midimapper_fetch_synth().

Sponsored by: The FreeBSD Foundation
MFC after: 2 days

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

This revision is now accepted and ready to land.Jun 29 2024, 6:36 PM

This pattern can be an area for concern as elements of scp may be modified while the lock is dropped. For instance, could scp->maxunits have a different value after dropping and retaking the lock?

This pattern can be an area for concern as elements of scp may be modified while the lock is dropped. For instance, could scp->maxunits have a different value after dropping and retaking the lock?

Yes, we cannot address LORs by simply dropping a lock, reacquiring it, and calling it fixed. Some analysis needs to be done to prove that such a change is correct, or a more extensive code change is needed.

sys/dev/sound/midi/sequencer.c
773

midimapper_open() is a weird function, it just counts the number of entries in the midi_devs list. Is there any reason we can't call it earlier, before acquiring seq_lock?

Or, can we introduce _locked variants of midimapper_open() and midimapper_fetch_synth() which assume that the lock is already held, and then modify this code to lock the midi state and use the _locked variants?

christos marked an inline comment as done.

Address Ed's and Mark's comments. Sorry for the lack of analysis. The _locked
variants approach Mark proposed works better. Calling midimapper_open() before
we lock seq_lock could work, but midimapper_fetch_synth() would need a _locked
variant anyway.

This revision now requires review to proceed.Jul 1 2024, 6:13 PM
sys/dev/sound/midi/midi.h
44

Instead of exposing the lock like this I could also implement lock/unlock functions, but I don't see a good reason for doing this.

sys/dev/sound/midi/midi.h
44

IMO it is usually better to hide the lock behind a function interface so that it's easier to change the lock type later without having to update all consumers, but it's up to you.

sys/dev/sound/midi/sequencer.c
810

You can release this lock earlier, there's no harm in that (since unlocking a mutex never blocks). I think it can be released right after the loop.

christos marked an inline comment as done.

Move sx_xunlock() after the loop.

sys/dev/sound/midi/midi.h
44

Since midi/midi.c also uses sx_x[un]lock() directly, I will keep it like this for now and implement a function interface for both midi.c and sequencer.c in a followup patch.

Looks fine, but are there other consumers of midimapper_open and midimapper_fetch_synth? Perhaps you can just replace the lock acquisition in those functions with the assertion, effectively providing only the locked variant?

Looks fine, but are there other consumers of midimapper_open and midimapper_fetch_synth? Perhaps you can just replace the lock acquisition in those functions with the assertion, effectively providing only the locked variant?

There are no other consumers of either function yet.

There are no other consumers of either function yet.

OK. It's fine this way if you want (so I clicked accept), but I'd suggest providing only the locked variant for now.

This revision is now accepted and ready to land.Jul 6 2024, 4:42 PM