안드로이드 오레오(Oreo)에서 커널을 강화한 이유과 그 결과

arm
linux

#1

게시자: Sami Tolvanen, Android Security 수석 소프트웨어 엔지니어

안드로이드의 사용자 공간이 강화됨에 따라 기본 Linux 커널이 공격자에게 점점 더 이목을 끄는 표적이 되고 있습니다. 그 결과, 지난해에 발견된 전체 안드로이드 보안 버그 중 1/3 이상이 커널에서 발견되었습니다. 안드로이드 8.0 오레오(Oreo)에서는 커널을 강화하여 보안 버그의 수와 영향을 줄이기 위해 상당한 노력을 쏟았습니다.

안드로이드 누가(Nougat)에서는 SELinux ioctl 필터링과 더불어 사용자 공간 프로세스로부터 커널을 분리하고 앱이 신뢰할 수 없는 입력 데이터를 처리할 때 사용 가능한 시스템 호출에 대한 액세스를 필터링할 수 있도록 허용하는 seccomp-bpf 지원을 요구함으로써 커널을 보호하기 위해 노력했습니다. 안드로이드 8.0에서는 업스트림 Linux로부터 이번 릴리스가 최초로 탑재된 기기에서 지원되는 모든 안드로이드 커널까지 4가지 보안 강화 기능이 백포트되는 커널 자체 보호에 초점을 맞춥니다.

강화된 usercopy

usercopy는 커널이 사용자 공간에서 커널 공간 메모리로 데이터를 전송하고 이를 다시 그 반대로 전송하기 위해 사용하는 함수입니다. 2014년 이후로 발생한 안드로이드 커널 취약점 중 45% 정도가 누락되거나 잘못된 경계 검사로 인한 것이었습니다. 강화된 usercopy는 usercopy 함수에 경계 검사를 추가하며, 이는 개발자가 코드에서 잘못 사용된 부분을 파악하고 버그를 수정하는 데 도움이 됩니다. 또한, 알려지지 않은 드라이버 버그를 놓치는 경우 이 함수를 강화함으로써 이와 같은 버그가 악용되지 않도록 방지할 수 있습니다. 이 기능은 업스트림 커널 버전 4.8에 도입되었으며, 우리는 이를 안드로이드 커널 3.18 이상에 백포트했습니다.

int buggy_driver_function(void __user *src, size_t size)
{
    /* potential size_t overflow (don’t do this) */
    u8 *buf = kmalloc(size * N, GPF_KERNEL);
    …
    /* results in buf smaller than size, and a heap overflow */
    if (copy_from_user(buf, src, size))
    return -EFAULT;

    /* never reached with CONFIG_HARDENED_USERCOPY=y */
}

강화된 usercopy로 방지되는 보안 문제의 예.

PAN(Privileged Access Never) 에뮬레이션

강화된 usercopy 함수는 보안 문제를 찾고 완화시키는 데 도움이 되기는 하지만, 개발자가 이런 함수를 실제로 사용할 경우에만 도움이 될 수 있습니다. 현재로서는 드라이버를 포함한 모든 커널 코드가 사용자 공간 메모리에 직접 액세스할 수 있으며, 이는 다양한 보안 문제를 초래할 수 있습니다. 이러한 문제를 줄이기 위해 CPU 공급업체는 x86에 SMAP(Supervisor Mode Access Prevention), ARM v8.1에 PAN(Privileged Access Never)과 같은 기능을 도입했습니다. 이러한 기능은 커널이 사용자 공간에 직접 액세스하지 못하게 막아하고 개발자가 usercopy 함수를 확실히 사용하도록 해줍니다. 안타깝게도 이러한 하드웨어 기능은 대부분의 안드로이드 사용자들이 현재 가지고 있는 기기에는 아직 널리 보급되지 않은 상태입니다. 업스트림 Linux에서는 커널 버전 4.3(ARM)4.10(ARM64) 에 PAN을 위한 소프트웨어 에뮬레이션을 도입했습니다. 우리는 3.18 버전부터 안드로이드 커널에 두 기능을 모두 백포트해왔습니다. 강화된 usercopy와 더불어, PAN 에뮬레이션은 Pixel 기기의 네 커널 드라이버에서 버그를 찾아 수정하는 데 도움이 되었습니다.

int buggy_driver_copy_data(struct mydata *src, void __user *ptr)
{
    /* failure to keep track of user space pointers */
    struct mydata *dst = (struct mydata *)ptr;
    …
    /* read/write from/to an arbitrary user space memory location */
    dst->field = … ;    /* use copy_(from|to)_user instead! */
    …
    /* never reached with PAN (emulation) or SMAP */
}

PAN 에뮬레이션으로 완화되는 보안 문제의 예.

커널 주소 공간 레이아웃 임의 지정(KASLR)

안드로이드에서는 수년 동안 주소 공간 레이아웃 임의 지정(ASLR) 기능을 지원하고 있습니다. 메모리 레이아웃을 임의 지정하면 코드 재사용 공격이 확률적으로 수행되도록 하므로 공격자가 코드를 악용하기 더 어려워지며, 특히 원격으로 공격하는 경우 더욱 어렵습니다. 안드로이드 8.0에서는 이 기능을 커널에 제공합니다. Linux는 버전 3.14부터 x86 기반 KASLR 을 지원해왔지만, ARM64용 KASLR 은 Linux 4.6 이후로 업스트림 버전으로만 제공되었습니다. 안드로이드 8.0에서는 안드로이드 커널 4.4 이상에서 KASLR을 사용할 수 있도록 지원합니다. KASLR은 부팅 시마다 커널 코드가 로드되는 위치를 임의 지정하여 커널 취약점을 완화시키는 데 도움이 됩니다. 예를 들어, ARM64에서 이 기능은 기기의 메모리 구성에 따라 13~25비트의 엔트로피를 추가하여 코드 재사용 공격을 더 어렵게 만듭니다.

초기화 후 읽기 전용 메모리

이 마지막 강화 기능은 커널이 초기화된 후 읽기 전용으로 표시된 메모리 영역을 생성하여 커널에서 활용되는 기존의 메모리 보호 기능을 확장합니다. 따라서 개발자는 초기화 도중에는 쓰기 가능한 상태여야 하지만 초기화 이후에는 수정 불가능한 상태가 되어야 하는 데이터에 대한 보호 능력을 향상시킬 수 있습니다. 쓰기 가능한 메모리를 줄일수록 커널의 내부 공격 표면이 줄어들어 악용하기가 더 어려워집니다. 초기화 후 읽기 전용 메모리는 업스트림 커널 버전 4.6에 도입되었으며, 우리는 이를 안드로이드 커널 3.18 이상으로 백포트했습니다. 우리는 코어 커널의 일부 데이터 구조체에만 이러한 보호 기능을 적용했지만, 이 기능은 커널 드라이버 작업을 수행하는 개발자들에게 극히 유용합니다.

결론

안드로이드 Oreo에는 커널에서 보안 버그를 가장 많이 일으키는 원인을 완화시키는 기능이 포함되어 있습니다. 안드로이드에서는 커널 보안 버그 중 85%가 엄격한 조사를 훨씬 덜 받는 편인 공급업체 드라이버에서 발생했으므로, 이는 특히 의의가 있는 일입니다. 드라이버 개발자는 이러한 업데이트 덕분에 더욱 쉽게 개발 과정에서 흔히 발생하는 버그를 발견하여 이들 버그가 최종 사용자 기기에 나타나기 전에 조기에 차단할 수 있습니다.

ref.

블로그 원문은 [여기](https://android-developers.googleblog.com/2017/08/hardening-kernel-in-android-oreo.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+blogspot/hsDu+(Android+Developers+Blog) 에서 확인하실 수 있습니다.