Samsung Android devices' kernels provide a character device under "/dev/tzic" which can be used to query the TrustZone OEM fuses.
One of the IOCTLs supported by the device is "TZIC_IOCTL_GET_FUSE_REQ". This IOCTL allows the user to query the OEM flag status. The code handling the IOCTL has the following logic:
static long tzic_ioctl(struct file *file, unsigned cmd, unsigned long arg) {
switch(cmd){
case TZIC_IOCTL_GET_FUSE_REQ:
LOG(KERN_INFO "[oemflag]get_fuse\n");
exynos_smc_read_oemflag(0x80010001, (u64 *) arg);
goto return_default;
break;
...
}
The "exynos_smc_read_oemflag" function issues an SMC to the Secure World in order to query the status of the OEM flag, but then writes this resulting value to the user supplied argument ("arg") without performing any validation. This allows an attacker to write the fuse's value to an address residing in kernel-space, thus corrupting kernel memory.
I have statically verified this issue using the open-source package for the Galaxy S6 Edge ("SM-G925V_NA_LL_Opensource"). I have also verified that this IOCTL is no longer present on the SM-G935V ("SM-G935V_NA_MM_Opensource").
Note that exploiting this issue requires elevated privileges. The /dev/tzic device can only be opened by the "system" UID (1000) and has an SELinux context of "u:object_r:tz_device:s0 tzic". The default SELinux policy as present on the SM-G925V permits access to this device from the following contexts:
allow icd tz_device : chr_file { ioctl read write getattr lock append open } ;
allow system_server tz_device : chr_file { ioctl read write getattr lock append open } ;
allow tzdaemon tz_device : chr_file { ioctl read write getattr lock append open } ;
allow commonplatformappdomain tz_device : chr_file { ioctl read write getattr lock append open } ;
allow system_app tz_device : chr_file { ioctl read getattr lock open } ;
allow s_system_app tz_device : chr_file { ioctl read getattr lock open } ;
This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.
Status: Invalid