On Wed, Jun 11, 2025 at 10:19:56AM -0700, Nicolin Chen wrote:
On Wed, Jun 11, 2025 at 10:04:35AM +0200, Thomas Weißschuh wrote:
On Wed, Jun 11, 2025 at 12:05:25AM -0700, Nicolin Chen wrote:
- parent doesn't seem to wait for the setup() to complete..
setup() is called in the child (L431) right before the testcase itself is called (L436). The parent waits for the child to exit (L439) before unmapping.
- when parent runs faster than the child that is still running setup(), the parent unmaps the no_teardown and set it to NULL, then UAF in the child, i.e. signal 11?
That should never happen as the waitpid() will block until the child running setup() and the testcase itself have exited.
Ah, maybe I was wrong about these narratives. But the results show that iommufd_dirty_tracking_teardown() was not called in the failed cases:
Here is a new finding...
As you replied that I was wrong about the race between the parent and the child processes, the parent does wait for the completion of the child. But the child exited with status=139 i.e. signal 11 due to UAF, which however is resulted from the iommufd test code:
FIXTURE_SETUP(iommufd_dirty_tracking) { .... vrc = mmap(self->buffer, variant->buffer_size, PROT_READ | PROT_WRITE, ^ | after this line, the _metadata->no_teardown is set to NULL.
So, the child process accessing this NULL pointer crashed with the signal 11..
And I did a further experiment by turning "bool *no_teardown" to a "bool no_teardown". Then, the mmap() in iommufd_dirty_tracking will set _metadata->teardown_fn function pointer to NULL..
Thanks Nicolin