[하루한줄] CVE-2021-3492: Ubuntu Shiftfs driver double free vulnerability

URL

EXPLOITATION OF A DOUBLE FREE VULNERABILITY IN UBUNTU SHIFTFS DRIVER (CVE-2021-3492)

Target

  • Ubuntu Groovy (20.10, kernel 5.8.0-50.56 이전 버전)
  • Ubuntu Focal (20.04, kernel 5.4.0-72.80 이전 버전)

Explain

Pwn2Own Vancouver 2021에서 Ubuntu Groovy (20.10)과 Ubuntu Focal (20.04)의 Shiftfs 드라이버에서 double free 버그가 발견되었습니다.

shiftfs는 파일 시스템 드라이버로 디렉터리를 bind-mount 하고 마운트한 user namespace owner의 맵을 통해 UID와 GID를 shift 할 수 있는 overlay 종류의 파일 시스템입니다. shiftfs는 특정 ioctl로 핸들링되며 허용된 ioctl을 전달받을 시 shiftfs_real_ioctl을 호출합니다. BTRFS_IOC_SNAP_CREATE ioctl이 사용되면 shiftfs_btrfs_ioctl_fd_replace 함수는 userspace에서 kernel space로 구조체를 복사하여 btrfs_ioctl_vol_args 구조체에 포함된 파일 디스크립터를 bottom 파일 시스템의 inode에 연결된 새 디스크립터로 교체하여 legacy btrfs ioctl을 래핑합니다.

이 ioctl이 shiftfs 파일에서 수행되면 핸들링 코드는 btrfs_ioctl_vol_args를 userpsace에서 kernel space로 복사합니다. 이 구조체에서 fd를 교체한 후 다시 userspace로 복사됩니다. 복사가 실패할 경우, copy_to_user 함수는 남아있는 바이트를 반환하여 양수 값을 반환합니다. 해당 함수를 호출하는 shiftfs_real_ioctl은 음수 값인지 확인하여 오류가 났는지 확인하여 오류가 발생하더라도 shiftfs_btrfs_ioctl_fd_restore를 호출하여 다른 copy_to_user를 실행하고 btrfs_ioctl_vol_args 구조체를 userpace로 보낸 다음 free 합니다.

shiftfs_btrfs_ioctl_fd_restore를 두 번 호출하면 같은 fd를 두 번 닫고 같은 구조체가 두 번 free 됩니다. 해당 구조체는 userspace에서 복사되는 동안 shiftfs_btrfs_ioctl_fd_replace에 할당되며 커널 함수 memdup_usercopy_from_user와 동시에 할당합니다.

shiftfs_btrfs_ioctl_fd_replace 함수에서 memdup_user가 할당에 성공하고 copy_to_user는 실패하면 shiftfs_btrfs_ioctl_fd_restore에서 kfree를 호출하여 첫 번째 free를 진행하고 shiftfs_real_ioctl에서 다시 shiftfs_btrfs_ioctl_fd_restore를 호출하여 Potential leak과 kfree를 통한 두 번째 free가 가능하여 double free bug가 발생합니다.