opnsense-src/sys
Kenneth D. Merry 8a6e5ade16 Fix mpr(4) and mps(4) state transitions and a use-after-free panic.
When the mpr(4) and mps(4) drivers probe a SATA device, they issue an
ATA Identify command (via mp{s,r}sas_get_sata_identify()) before the
target is fully setup in the driver.  The drivers wait for completion of
the identify command, and have a 5 second timeout.  If the timeout
fires, the command is marked with the SATA_ID_TIMEOUT flag so it can be
freed later.

That is where the use-after-free problem comes in.  Once the ATA
Identify times out, the driver sends a target reset, and then frees any
identify commands that have timed out.  But, once the target reset
completes, commands that were queued to the drive are returned to the
driver by the controller.

At that point, the driver (in mp{s,r}_intr_locked()) looks up the
command descriptor for that particular SMID, marks it CM_STATE_BUSY and
sends it on for completion handling.

The problem at this stage is that the command has already been freed,
and put on the free queue, so its state is CM_STATE_FREE.  If INVARIANTS
are turned on, we get a panic as soon as this command is allocated,
because its state is no longer CM_STATE_FREE, but rather CM_STATE_BUSY.

So, the solution is to not free ATA Identify commands that get stuck
until they actually return from the controller.  Hopefully this works
correctly on older firmware versions.  If not, it could result in
commands hanging around indefinitely.  But, the alternative is a
use-after-free panic or assertion (in the INVARIANTS case).

This also tightens up the state transitions between CM_STATE_FREE,
CM_STATE_BUSY and CM_STATE_INQUEUE, so that the state transitions happen
once, and we have assertions to make sure that commands are in the
correct state before transitioning to the next state.  Also, for each
state assertion, we print out the current state of the command if it is
incorrect.

mp{s,r}.c:      Add a new sysctl variable, dump_reqs_alltypes,
                that controls the behavior of the dump_reqs sysctl.
                If dump_reqs_alltypes is non-zero, it will dump
                all commands, not just the commands that are in the
                CM_STATE_INQUEUE state.  (You can see the commands
                that are in the queue by using mp{s,r}util debug
                dumpreqs.)

                Make sure that the INQUEUE -> BUSY state transition
                happens in one place, the mp{s,r}_complete_command
                routine.

mp{s,r}_sas.c:  Make sure we print the current command type in
                command state assertions.

mp{s,r}_sas_lsi.c:
                Add a new completion handler,
                mp{s,r}sas_ata_id_complete.  This completion
                handler will free data allocated for an ATA
                Identify command and free the command structure.

                In mp{s,r}_ata_id_timeout, do not set the command
                state to CM_STATE_BUSY.  The command is still in
                queue in the controller.  Since we were blocking
                waiting for this command to complete, there was
                no completion handler previously.  Set the
                completion handler, so that whenever the command
                does come back, it will get freed properly.

                Do not free ATA Identify commands that have timed
                out in mp{s,r}sas_add_device().  Wait for them
                to actually come back from the controller.

mp{s,r}var.h:   Add a dump_reqs_alltypes variable for the new
                dump_reqs_alltypes sysctl.

                Make sure we print the current state for state
                transition asserts.

This was tested in the Spectra Logic test bed (as described in the
review), as well Netflix's Open Connect fleet (where panics dropped from
a dozen or two a month to zero).

Reviewed by:		imp@ (who is handling the commit with ken's OK)
Sponsored by:		Spectra Logic
Differential Revision:	https://reviews.freebsd.org/D25476

(cherry picked from commit 175ad3d003)
2021-09-02 20:33:28 -04:00
..
amd64 amd64: remove lfence after swapgs on syscall entry 2021-09-02 03:52:24 +03:00
arm Revert "arm: Bump KSTACK_PAGES default to match i386/amd64" 2021-09-02 07:56:25 -07:00
arm64 pmap: Micro-optimize pmap_remove_pages() on amd64 and arm64 2021-09-01 09:29:01 -04:00
bsm Add aio_writev and aio_readv 2021-01-02 19:57:58 -07:00
cam cam(4): Mark all sysctls as CTLFLAG_MPSAFE. 2021-08-24 21:53:17 -04:00
cddl fbt: Remove some handling for multiple CTF containers 2021-04-15 21:27:24 -04:00
compat linuxkpi: remove global atomic counter of the task allocations 2021-08-03 12:56:02 +03:00
conf Don't error out on unused but set variables with clang 13 2021-09-02 23:53:18 +02:00
contrib Fix acpica macros that subtract null pointers 2021-09-02 23:53:18 +02:00
crypto armv8crypto: note derivation in armv8_crypto_wrap.c 2021-03-22 13:14:51 -03:00
ddb ddb: reliably fail with ambiguous commands 2021-07-02 14:13:24 -07:00
dev Fix mpr(4) and mps(4) state transitions and a use-after-free panic. 2021-09-02 20:33:28 -04:00
dts arm: allwinner: dtb: Add overlays to disable SD/MMC node 2021-07-22 19:29:21 +02:00
fs ext2fs(5): Correct a typo in an error message 2021-08-29 08:12:08 +02:00
gdb gdb: report specific stop reason for watchpoints 2021-04-21 10:20:33 -03:00
geom Fix some common typos in source code comments 2021-08-31 08:13:15 +02:00
gnu Remove the old dts imported tree. 2021-01-15 20:09:55 +01:00
i386 Style 2021-09-02 03:52:24 +03:00
isa Remove more remnants of sio(4) 2021-04-14 09:19:49 -04:00
kern fsetown: Avoid process group lock recursion 2021-09-01 09:07:39 -04:00
kgssapi
libkern Switch to an ifunc in the kernel for crc32c 2021-08-30 12:22:21 +01:00
mips Add pmap_vm_page_alloc_check() 2021-08-24 02:21:13 +03:00
modules MFC 517904de5c: igc(4): Introduce new driver for the Intel I225 Ethernet controller. 2021-08-15 20:33:54 +10:00
net if_bridge: add ALTQ support 2021-09-01 15:27:01 +02:00
net80211 net80211/LinuxKPI: add more radiotap definitions 2021-07-18 00:35:03 +00:00
netgraph ng_bridge: Use M_NOWAIT when allocating memory in the newhook routine 2021-08-20 08:42:43 -04:00
netinet inet(3): Fix a few common typos in source code comments 2021-08-31 08:11:48 +02:00
netinet6 inet6(4): Fix a few common typos in source code comments 2021-08-31 08:11:24 +02:00
netipsec netipsec/key.c: Use ANSI C definition for key_random() 2021-08-13 12:34:42 +03:00
netpfil ipfw: use unsigned int for dummynet bandwidth 2021-08-26 14:05:26 +02:00
netsmb netsmb: Avoid a read-after-free in smb_t2_request_int() 2021-06-02 09:34:47 -04:00
nfs
nfsclient
nfsserver
nlm
ofed Fix mismerge in OFED update 2021-07-26 18:12:35 +02:00
opencrypto cryptodev: Fix some input validation bugs 2021-05-14 09:58:54 -04:00
powerpc Add pmap_vm_page_alloc_check() 2021-08-24 02:21:13 +03:00
riscv Add pmap_vm_page_alloc_check() 2021-08-24 02:21:13 +03:00
rpc rpc: Make function tables const 2021-08-21 12:10:31 -04:00
security mac: cheaper check for ifnet_create_mbuf and ifnet_check_transmit 2021-07-05 11:32:14 +00:00
sys pci: Add an ioctl to perform I/O to BARs 2021-08-29 12:39:42 -04:00
teken loader: implement framebuffer console 2021-01-02 21:41:36 +02:00
tests tests: Revise FIB lookups per second benchmarking routines 2021-06-20 13:27:17 +02:00
tools makesyscalls.lua: improve generated file style(9) compliance 2021-05-19 20:31:54 -04:00
ufs ufs_dirhash: Correct a typo in a comment 2021-08-23 08:32:50 +02:00
vm Add pmap_vm_page_alloc_check() 2021-08-24 02:21:13 +03:00
x86 xen: Fix warning by adding KERNBASE to modlist_paddr before casting 2021-09-02 23:53:18 +02:00
xdr
xen xen: remove .swp file from public headers 2021-01-11 18:14:11 +01:00
Makefile