Re: [PATCH] USB: OHCI: Don't mark EDs as ED_OPER if scheduling fails

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> If the list pointer contains LIST_POISON then it's already too late; 
> we've been accessing memory that was deallocated.

Not really. I figured that LIST_POISON happens if the ED had been
linked and unlinked normally before being submitted abnormally.
And in fact, knowing that, I justs managed to reproduce this crash:

# Start X with USB mouse, HID submits some URBs
[   22.860629] ohci-pci 0000:00:12.0: link ed ffff8800df04c070 branch 0 [92us.], interval 8
[   36.221548] fuse init (API version 7.23)
# Stop X, HID pauses
[   48.435810] ohci-pci 0000:00:12.0: unlink ed ffff8800df04c070 branch 0 [92us.], interval 8
# Connect the modem and steal the mouses's bandwidth
[   87.617143] ohci-pci 0000:00:12.0: rhsc
[   87.622003] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00010101 CSC PPS CCS
[   87.827192] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000113
[   87.887247] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   87.947278] usb 1-1: new full-speed USB device number 4 using ohci-pci
[   87.977299] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000113
[   88.037325] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   88.175069] NET: Registered protocol family 8
[   88.179452] NET: Registered protocol family 20
[   88.196990] usb 1-1: [ueagle-atm] ADSL device founded vid (0X1110) pid (0X9032) Rev (0X2000): Eagle III
[   88.201451] ohci-pci 0000:00:12.0: rhsc
[   88.227503] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000113
[   88.230733] ohci-pci 0000:00:12.0: rhsc
[   88.287502] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   88.347514] usb 1-1: reset full-speed USB device number 4 using ohci-pci
[   88.377554] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000113
[   88.381932] ohci-pci 0000:00:12.0: rhsc
[   88.437560] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   88.532329] usb 1-1: [ueagle-atm] pre-firmware device, uploading firmware
[   88.536583] usb 1-1: [ueagle-atm] loading firmware ueagle-atm/eagleIII.fw
[   88.540877] usbcore: registered new interface driver ueagle-atm
[   89.849038] usb 1-1: [ueagle-atm] firmware uploaded
[   89.874678] ohci-pci 0000:00:12.0: rhsc
[   89.879085] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00030100 PESC CSC PPS
[   89.883498] usb 1-1: USB disconnect, device number 4
[   92.019520] ohci-pci 0000:00:12.0: rhsc
[   92.024128] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00010101 CSC PPS CCS
[   92.179643] ohci-pci 0000:00:12.0: rhsc
[   92.209245] ohci-pci 0000:00:12.0: rhsc
[   92.213738] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000111
[   92.269662] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   92.329671] usb 1-1: new full-speed USB device number 5 using ohci-pci
[   92.359715] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000113
[   92.419743] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   92.572667] usb 1-1: [ueagle-atm] ADSL device founded vid (0X1110) pid (0X9031) Rev (0X200B): Eagle III
[   92.599827] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000113
[   92.659867] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   92.719894] usb 1-1: reset full-speed USB device number 5 using ohci-pci
[   92.749921] ohci-pci 0000:00:12.0: port[0] reset timeout, stat 00000113
[   92.809973] ohci-pci 0000:00:12.0: GetStatus roothub.portstatus [0] = 0x00100103 PRSC PPS PES CCS
[   92.962755] usb 1-1: [ueagle-atm] using iso mode
[   92.967497] ohci-pci 0000:00:12.0: link ed ffff8800df04c150 branch 0 [35us.], interval 1
[   92.975753] ohci-pci 0000:00:12.0: link iso ed ffff8800df04c1c0 branch 0 [793us.], interval 1
[   92.980543] usb 1-1: [ueagle-atm] (re)booting started
[   94.682703] usb 1-1: [ueagle-atm] ATU-R firmware version : 44e2ea17
[   94.696215] usb 1-1: [Ueagle-atm] firmware ueagle-atm/CMVep.bin.v2 is corrupted, try to get older cmvs
[   94.701136] usb 1-1: [Ueagle-atm] use deprecated cmvs version, please update your firmware
[   94.737733] usb 1-1: [ueagle-atm] modem started, waiting synchronization...
# Start X, HID resumes
[   97.953708] ohci-pci 0000:00:12.0: ERR -28, interval 8 msecs, load 92
# ENOSPC, mouse doesn't work this time, but ed->state became ED_OPER
# Stop X, nothing happens
# Start X, ed_schedule bypassed thanks to ED_OPER, mouse works
# Stop X, we hit LIST_POISON on unlinking
[  143.457333] ohci-pci 0000:00:12.0: unlink ed ffff8800df04c070 branch0 [92us.], interval 8
[  143.457548] list_del: ffff8800df04c070 dead000000000100
# Start X, previous unlink() decreased ohci->load so ed_schedule passes
[  162.648710] ohci-pci 0000:00:12.0: link ed ffff8800df04c070 branch 0 [92us.], interval 8
# Stop X
[  181.477893] ohci-pci 0000:00:12.0: unlink ed ffff8800df04c070 branch0 [92us.], interval 8


Now, this doesn't prove that use-after-free is not possible in some
other, more convoluted cases.

However, these out-of-sched transactions appear to work and their
completion seems to be reported to the upper layers just fine.
This gives *some* hope that the transaction retirement code is working
properly and that by the time the upper layers call endpoint_disable
(the only place freeing EDs), all pointers to this ED are gone.

> (This shouldn't happen, though, because the ED structures are
> allocated from a coherent DMA pool.)

The only way I can see this helping with use-after-free is that when
somebody overwrites our freed ED with something, at least it's going to
be another ED and not totally random garbage.

Still, it means we are now modifying the same ED someone else uses and
there's going to be a lot more trouble than just this unlinking thing.

I don't think use-after-free is salvageable in any way.

> They could contain a different value, though -- stale pointers
> from an earlier time when they _were_ on the list.

Nope, that's why list_del sets pointers to LIST_POISON. Those fields
can only contain valid address (the normal case, unless we are "sharing"
ED with someone else) or LIST_POISON or NULL (ed_alloc zeros them).

> The best way to protect against this is to call INIT_LIST_HEAD in
> ed_alloc() and list_del_init() in finish_unlinks().

This means silently sweeping a whole class of bugs under the rug.
I wouldn't want to have this in mainline. And as for longterm, I think
my approach has the advantage of not pretending to be anything more than
just a nasty hack to keep thing from burning.

Though, on second thought, I'm not sure if preventing this panic is a
good idea at all. We still don't know what kind of dark powers allow
these EDs to bypass periodic_link and cannot prove that there won't
be some memory corruption *after* the evaded crash, even if the evasion
itself happens "legally", before ed_free.

Maybe it's safer to just let things burn.

Regards,
MP
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux