[하루한줄] CVE-2024-44068: Samsung Exynos UAF 취약점

URL

https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2024/CVE-2024-44068.html

Target

  • Samsung Exynos (9820, 9825, 980, 990, 850, W920) < SMR-Oct-2024

Explain

삼성의 모바일 및 웨어러블 프로세서인 Exynos에서 UAF 취약점이 발견되어 Google Project Zero의 세부 분석 정보가 공개되었습니다.

취약점은 미디어의 하드웨어 가속을 제공하는 m2m 드라이버의 M2M1SHOT_IOC_PROCESS IOCTL 루틴에 존재합니다. 해당 루틴은 유저랜드 페이지를 I/O 페이지에 매핑 및 매핑 해제하고, 펌웨어 명령을 실행합니다.

I/O 메모리 매핑 시 m2m1shot_dma_addr_mapexynos_iovmm_map_userptrexynos_iommu_map_userptrsysmmu_map_pud 호출 체인을 통해 sysmmu_map_pte 함수가 호출됩니다.

참조된 Github 링크는 설명을 위한 예시이며, exploit 및 분석 환경과 일치하지 않을 수 있습니다.

static int sysmmu_map_pte(struct mm_struct *mm,
		pmd_t *pmd, unsigned long addr, unsigned long end,
		struct exynos_iommu_domain *domain, sysmmu_iova_t iova, int prot)
{
	pte_t *pte;
	int ret = 0;
	spinlock_t *ptl;
	bool write = !!(prot & IOMMU_WRITE);
	bool pfnmap = !!(prot & IOMMU_PFNMAP);  // [1] If vma->vm_flags & VM_PFNMAP is true, exynos_iovmm_map_userptr appends the IOMMU_PFNMAP flag to prot.
	bool shareable = !!(prot & IOMMU_CACHE);
	unsigned int fault_flag = write ? FAULT_FLAG_WRITE : 0;
	sysmmu_pte_t *ent, *ent_beg;

	pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
	if (!pte)
		return -ENOMEM;

	ent = alloc_lv2entry_userptr(domain, iova);
	if (IS_ERR(ent)) {
		ret = PTR_ERR(ent);
		goto err;
	}

	ent_beg = ent;

	do {
		if (pte_none(*pte) || !pte_present(*pte) ||
					(write && !pte_write(*pte))) {
			int cnt = 0;
			int maxcnt = 1;

			if (pfnmap) {
				ret = -EFAULT;
				goto err;
			}

			while (cnt++ < maxcnt) {
				spin_unlock(ptl);
				/* find_vma() always successes */
				ret = handle_mm_fault(find_vma(mm, addr),
						addr, fault_flag);
				spin_lock(ptl);
				if (ret & VM_FAULT_ERROR) {
					ret = mm_fault_translate(ret);
					goto err;
				} else {
					ret = 0;
				}
				[...]
			}
		}

		BUG_ON(!lv2ent_fault(ent));

		*ent = mk_lv2ent_spage(pte_pfn(*pte) << PAGE_SHIFT);

		if (!pfnmap)
			get_page(pte_page(*pte));
		else
			mk_lv2ent_pfnmap(ent);	// [2] For PFNMAP pages, the page reference count is not elevated.

		[...]
	} while (pte++, addr += PAGE_SIZE, addr != end);

	pgtable_flush(ent_beg, ent);
err:
	pte_unmap_unlock(pte - 1, ptl);
	return ret;
}

해당 함수는 FNMAP 페이지에 대한 referece count를 증가시키지 않으며, 호출 체인 중exynos_iommu_unmap_userptr 함수에서 non-PFNMAP 페이지에 대한 reference count만 감소시킵니다.

따라서 PFNMAP 페이지를 할당하고, 이를 I/O Virtual Memory에 매핑한 뒤 참조된 상태의 페이지를 munmap을 통해 해제할 수 있습니다. 매핑되어있는 I/O Virtual Memory는 여전히 해제된 페이지에 접근이 가능하므로 UAF가 트리거됩니다.

해당 취약점은 In-The-Wild에서 악용된 취약점이며, 공격자는 해당 취약점을 악용해 권한있는 프로세스인 cameraserver 프로세스에서 임의 코드를 실행한 것으로 알려졌습니다.