Google Android - 'pm_qos' KASLR Bypass

EDB-ID:

41161

CVE:





Platform:

Android

Date:

2017-01-26


Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=971

The "pm_qos" module exposes an interface to kernel space for specifying QoS dependencies. In order to aid in debugging this interface, the module exposes a "debugfs" interface, available under:

/sys/kernel/debug/pm_qos

This file is world-readable, and allows any user to query the current QOS constraints. The code which prints out each constraint is available under the "pm_qos_debug_show_one" function in the file "kernel/power/qos.c". Here is the code for this function:

static void pm_qos_debug_show_one(struct seq_file *s, struct pm_qos_object *qos)
{
    struct plist_node *p;
    unsigned long flags;

    spin_lock_irqsave(&pm_qos_lock, flags);

    seq_printf(s, "%s\n", qos->name);
    seq_printf(s, "   default value: %d\n", qos->constraints->default_value);
    seq_printf(s, "   target value: %d\n", qos->constraints->target_value);
    seq_printf(s, "   requests:\n");
    plist_for_each(p, &qos->constraints->list)
        seq_printf(s, "      %pk(%s:%d): %d\n",
                      container_of(p, struct pm_qos_request, node),
                      (container_of(p, struct pm_qos_request, node))->func,
                      (container_of(p, struct pm_qos_request, node))->line,
                      p->prio);

    spin_unlock_irqrestore(&pm_qos_lock, flags);
}

As seen above, the function prints out the QOS constraint entries (which are static variables stored in the kernel's BSS). To avoid leaking the BSS addresses to unprivileged users, the function uses the format specifier "%pk". Note that the 'k' character in this format specifier is lowercase, instead of the correct specifier - "%pK" (using an uppercase 'K'). As format specifiers are case-sensitive, the "vsnprintf" implementation simply ignores the lowercase 'k' - therefore always printing the pointer above.

For devices with Samsung KNOX v2.6 (e.g., Galaxy S7 and Galaxy S7 Edge), this allows an attacker to bypass KASLR. This is since the BSS and the kernel's code have the same KASLR "slide" value. An attacker can read the QOS constraint addresses from the "sysfs" entry and compare them to the calculated base address of the kernel's BSS in order to find the value of the KASLR slide.

This issue can be addressed by fixing the format specifier to "%pK".

Although the original code for the "pm_qos" is written by Intel, I could only trace back this specific code snippet ("pm_qos_debug_show_one") to Samsung kernels. Therefore, I am assuming that this specific code has been added by Samsung at a certain point. If this is not the case, please let me know so that I can report this issue to the additional parties.

I've statically verified this issue on an SM-G935F device. The open-source kernel package I analysed was "SM-G935F_MM_Opensource".

The sysfs entries mentioned above are world-readable and have an SELinux context of: "u:object_r:debugfs:s0". According to the default SELinux rules as present on the SM-G935F (version XXS1APG3), the following contexts may access these files:

   allow ipm debugfs : file { ioctl read getattr lock open } ; 
   allow RIDL debugfs : file read ; 
   allow secure_storage debugfs : dir { ioctl read getattr search open } ; 
   allow knox_system_app debugfs : dir { ioctl read getattr search open } ; 
   allow debuggerd debugfs : file { ioctl read getattr lock open } ; 
   allow trusteddomain debugfs : file { read getattr } ; 
   allow bluetooth debugfs : file read ; 
   allow knox_system_app debugfs : file { ioctl read getattr lock open } ; 
   allow system_app debugfs : file { ioctl read getattr lock open } ; 
   allow slogmodem debugfs : file read ; 
   allow slogd debugfs : file { ioctl read getattr lock open } ; 
   allow debugfs debugfs : filesystem associate ; 
   allow domain debugfs : file { write append open } ; 
   allow mediaserver debugfs : file { ioctl read write create getattr setattr lock append unlink rename open } ; 
   allow debuggerd debugfs : dir { ioctl read getattr search open } ; 
   allow domain debugfs : dir { ioctl read getattr search open } ; 
   allow cmd_services debugfs : file read ; 
   allow dumpstate debugfs : file { ioctl read write getattr lock append open } ; 
   allow secure_storage debugfs : file { ioctl read getattr lock open } ; 
   allow wcnd debugfs : file read ; 
   allow init debugfs : file getattr ; 
   allow system_server debugfs : file { ioctl read getattr lock open } ; 
   allow untrusteddomain debugfs : file execute ; 
   allow shell debugfs : file { ioctl read getattr lock open } ; 
   allow surfaceflinger debugfs : file { ioctl read getattr lock open } ;


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41161.zip