Re: [PATCH v6 12/15] s390/vfio-ap: Transition device migration state from STOP to RUNNING and vice versa
Anthony Krowiak <[email protected]> Wed, 5 Aug 2026 09:14:36 -0400
| Newsgroups | dev.linux.lists.sashiko-reviews,org.kernel.vger.kvm,org.kernel.vger.linux-s390 |
|---|---|
| Message-ID | <[email protected]> |
On 7/27/26 2:28 PM, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: > - [Critical] Concurrent device reset, closure, or state transitions during migration data transfer cause Use-After-Free or Write-After-Free of `ap_config`. > - [High] Overwriting the active migration file descriptor during state transitions allows silent migration of stale state and leaks file references. > -- > > --- Patch [12]: [PATCH v6 12/15] s390/vfio-ap: Transition device migration state from STOP to RUNNING and vice versa --- > commit 2b837152c9f64c5082507b5aa41ffc56027c1e29 > Author: Anthony Krowiak <[email protected]> > > s390/vfio-ap: Transition device migration state from STOP to RUNNING and vice versa > > The transition from STOP to RUNNING and vice versa indicates that > the vfio device is operating normally and migration is not > currently taking place. In this case, just set the new state. > >> diff --git a/drivers/s390/crypto/vfio_ap_migration.c b/drivers/s390/crypto/vfio_ap_migration.c >> index fc4cb893f0f00..1c385908fc39b 100644 >> --- a/drivers/s390/crypto/vfio_ap_migration.c >> +++ b/drivers/s390/crypto/vfio_ap_migration.c >> @@ -1280,12 +1280,17 @@ vfio_ap_transition_to_state(struct ap_matrix_mdev *matrix_mdev, > [ ... ] >> + /* >> + * These states indicate migration has either not been initiated or >> + * has completed and the vfio-ap device is operating normally. Since the >> + * vfio-ap device does not virtualize a DMA device, there is no internal >> + * device state to incorporate into the vfio-ap device on the target. >> + */ >> if ((cur_state == VFIO_DEVICE_STATE_STOP && >> new_state == VFIO_DEVICE_STATE_RUNNING) || >> (cur_state == VFIO_DEVICE_STATE_RUNNING && >> new_state == VFIO_DEVICE_STATE_STOP)) { >> - /* TODO */ >> - return ERR_PTR(-EOPNOTSUPP); >> + return NULL; > [Severity: High] > Does returning NULL here instead of -EOPNOTSUPP allow userspace to silently > leak the active migration file and state? > > If a live migration is aborted and transitioned gracefully from STOP to > RUNNING, the old file descriptor could remain active in mig_data because > the driver still holds a reference to the file. > > If the process later starts a new migration and transitions to STOP_COPY > again, it looks like vfio_ap_transition_to_state() unconditionally > overwrites mig_data->stop_copy_mig_file.filp: > > vfio_ap_transition_to_state() { > ... > if (cur_state == VFIO_DEVICE_STATE_STOP && > new_state == VFIO_DEVICE_STATE_STOP_COPY) { > ... > mig_data->stop_copy_mig_file.filp = filp; > return filp; > } > ... > } > > Will this cause the driver's reference to the old file to be permanently lost? > > If the old fd is read, vfio_ap_stop_copy_read() might observe that > mig_file->ap_config is already populated and skip updating it, serving > stale configuration to the target. > > Additionally, when userspace closes the old fd, its release handler might > fail to match the overwritten filp pointer, which would skip > vfio_device_put_registration() and permanently pin the device. The NULL return for STOP<->RUNNING transitions is the correct VFIO API response when no data fd needs to be handed to userspace — it does not touch any filp field in mig_data. The scenario you describe — a new STOP->STOP_COPY transition silently overwriting a still-live stop_copy_mig_file.filp — cannot happen, for the following reasons: File descriptor cleanup is always performed before a new fd can be opened. vfio_ap_release_mig_files() is called by both vfio_ap_reset_migration_state() (on VFIO_DEVICE_RESET) and vfio_ap_release_migration_data() (on device close), both under mdevs_lock. Either path nulls out stop_copy_mig_file.filp before any subsequent STOP->STOP_COPY transition can reach the code that writes to it. vfio_device_put_registration() is always balanced. vfio_ap_release_mig_file() — the file_operations.release handler invoked when userspace closes the fd — unconditionally calls vfio_device_put_registration() regardless of mig_data state. There is no code path that causes it to be skipped. The stale-data scenario does not apply. validate_stop_copy_read_parms() rejects any read where mig_data->stop_copy_mig_file.filp != filp. A fd from a previous session will fail that check with -EINVAL and never serve any data. > > [Severity: Critical] > With these new state transitions, is there also a risk of use-after-free or > write-after-free regressions during concurrent migration data transfers? > > If a userspace process calls read() or write() on the migration file > descriptor, mdevs_lock is temporarily dropped during the data copy: > > vfio_ap_stop_copy_read() { > ... > mutex_unlock(&matrix_dev->mdevs_lock); > > if (copy_to_user(buf, (char *)mig_file->ap_config + read_pos, len)) > ... > } > > Similarly in vfio_ap_resuming_write(): > > vfio_ap_resuming_write() { > ... > mutex_unlock(&matrix_dev->mdevs_lock); > > if (copy_from_user((char *)ap_config + write_pos, buf, len)) { > ... > } > > Can a concurrent thread issue a VFIO_DEVICE_RESET ioctl, close the > device fd, or trigger a state transition that acquires mdevs_lock and > frees ap_config and mig_data? > > If so, when the read/write thread resumes execution, it appears it > would access the freed ap_config memory, leading to arbitrary kernel > memory corruption or information leaks. This is a valid observation. At the commit under review, vfio_ap_resuming_write() drops mdevs_lock for copy_from_user() while holding a raw pointer to an ap_config buffer that has not yet been stored into mig_data. For subsequent writes (non-new-allocation path), the pointer is retrieved from mig_data->resuming_mig_file.ap_config under the lock but then used after the lock is dropped. A concurrent VFIO_DEVICE_RESET calling vfio_ap_release_mig_files() under the same lock could kvfree() that buffer while the write path is copying into it. This will be addressed in the next patch series. > >> } >> >> /* vfio_mig_get_next_state() does not use arcs other than the above */