Re: [PATCH] mm/gup_test: fix race with PIN_LONGTERM_TEST ioctls
From: David Hildenbrand (Arm)
Date: Fri Jun 12 2026 - 03:38:11 EST
On 6/8/26 04:50, Yunhui Cui wrote:
> The PIN_LONGTERM_TEST helpers keep their state in global variables that
> are protected by pin_longterm_test_mutex when accessed from ioctl().
> However, gup_test_release() calls pin_longterm_test_stop() without
> holding that mutex.
>
> This can race with PIN_LONGTERM_TEST_STOP and let two callers operate on
> the same pages array concurrently, corrupting the test state and possibly
> freeing it twice:
>
> CPU 0 CPU 1
> ----- -----
> ioctl(PIN_LONGTERM_TEST_STOP)
> mutex_lock(&pin_longterm_test_mutex)
> pin_longterm_test_stop()
> if (pin_longterm_test_pages)
> kvfree(pin_longterm_test_pages)
>
> close()
> gup_test_release()
> pin_longterm_test_stop()
> if (pin_longterm_test_pages)
> kvfree(pin_longterm_test_pages)
>
> pin_longterm_test_pages = NULL
> mutex_unlock(&pin_longterm_test_mutex)
Okay, thinking about this some more ...
I think what's really required here is that we have two separate "struct file",
because otherwise release() cannot race with unlocked_ioctl().
Which is something we didn't expect when we added this functionality.
I think the proper way to handle this is by moving the state to the
"struct file", to actually cleanly allow concurrent usage.
So instead, I think we should do the following (untested):