🇰🇷 한글 설명
Linux 커널의 USB gadget f_fs 구성 요소에서 aio_cancel() 호출과 AIO 요청 완료 처리 간의 레이스 컨디션(경쟁 상태) 취약점이 발견되었습니다. 소프트 디스커넥트 상황에서 두 프로세스가 동시에 실행될 경우, 이미 해제된 USB 요청 객체에 접근하여 잘못된 포인터를 참조할 수 있습니다.
💡 쉬운 설명
USB 장치 연결이 끊기는 순간에 데이터 요청을 취소하려는 동작이 동시에 일어나면서 컴퓨터 메모리 관리 오류가 발생하는 문제입니다. 이로 인해 시스템이 불안정해지거나 예상치 못한 동작이 발생할 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
usb: gadget: f_fs: Fix race between aio_cancel() and AIO request complete
FFS based applications can utilize the aio_cancel() callback to dequeue
pending USB requests submitted to the UDC. There is a scenario where the
FFS application issues an AIO cancel call, while the UDC is handling a
soft disconnect. For a DWC3 based implementation, the callstack looks
like the following:
DWC3 Gadget FFS Application
dwc3_gadget_soft_disconnect() ...
--> dwc3_stop_active_transfers()
--> dwc3_gadget_giveback(-ESHUTDOWN)
--> ffs_epfile_async_io_complete() ffs_aio_cancel()
--> usb_ep_free_request() --> usb_ep_dequeue()
There is currently no locking implemented between the AIO completion
handler and AIO cancel, so the issue occurs if the completion routine is
running in parallel to an AIO cancel call coming from the FFS application.
As the completion call frees the USB request (io_data->req) the FFS
application is also referencing it for the usb_ep_dequeue() call. This can
lead to accessing a stale/hanging pointer.
commit b566d38857fc ("usb: gadget: f_fs: use io_data->status consistently")
relocated the usb_ep_free_request() into ffs_epfile_async_io_complete().
However, in order to properly implement locking to mitigate this issue, the
spinlock can't be added to ffs_epfile_async_io_complete(), as
usb_ep_dequeue() (if successfully dequeuing a USB request) will call the
function driver's completion handler in the same context. Hence, leading
into a deadlock.
Fix this issue by moving the usb_ep_free_request() back to
ffs_user_copy_worker(), and ensuring that it explicitly sets io_data->req
to NULL after freeing it within the ffs->eps_lock. This resolves the race
condition above, as the ffs_aio_cancel() routine will not continue
attempting to dequeue a request that has already been freed, or the
ffs_user_copy_work() not freeing the USB request until the AIO cancel is
done referencing it.
This fix depends on
commit b566d38857fc ("usb: gadget: f_fs: use io_data->status
consistently")
📍 영향받는 시스템
Linux kernel (USB gadget f_fs 및 DWC3 기반 구현 사용 시스템)
⚔️ 공격 벡터
FFS 기반 애플리케이션을 통해 특정 타이밍에 AIO 취소 요청을 보내 레이스 컨디션을 유도
🛡️ 대응 방법
커널 패치(commit b566d38857fc 관련 수정 사항 포함)를 적용하여 usb_ep_free_request() 호출 위치를 변경하고 락(lock)을 통해 동기화 수행
🔧 검증 코드
현재 실행 중인 커널 버전을 확인하여 취약점이 해결된 패치 버전이 적용되었는지 확인