Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=958 The following code in frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp doesn't validate the parameter params.num_bssid, and then copies that number of elements into a stack-allocated wifi_bssid_hotlist_params structure. I don't think this can be reached from an untrusted_app context; but it can be reached from a context with system_api_service access; so a compromised platform app or one of several lower privileged system services (bluetooth, nfc etc.). static jboolean android_net_wifi_setHotlist( JNIEnv *env, jclass cls, jint iface, jint id, jobject ap) { JNIHelper helper(env); wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); ALOGD("setting hotlist on interface[%d] = %p", iface, handle); wifi_bssid_hotlist_params params; memset(¶ms, 0, sizeof(params)); params.lost_ap_sample_size = helper.getIntField(ap, "apLostThreshold"); JNIObject array = helper.getArrayField( ap, "bssidInfos", "[Landroid/net/wifi/WifiScanner$BssidInfo;"); params.num_bssid = helper.getArrayLength(array); if (params.num_bssid == 0) { ALOGE("setHotlist array length was 0"); return false; } for (int i = 0; i < params.num_bssid; i++) { // <--- no validation on num_bssid JNIObject objAp = helper.getObjectArrayElement(array, i); JNIObject macAddrString = helper.getStringField(objAp, "bssid"); if (macAddrString == NULL) { ALOGE("Error getting bssid field"); return false; } ScopedUtfChars chars(env, macAddrString); const char *bssid = chars.c_str(); if (bssid == NULL) { ALOGE("Error getting bssid"); return false; } parseMacAddress(bssid, params.ap[i].bssid); // <--- params.ap has 128 elements. mac_addr addr; memcpy(addr, params.ap[i].bssid, sizeof(mac_addr)); char bssidOut[32]; snprintf(bssidOut, sizeof(bssidOut), "%0x:%0x:%0x:%0x:%0x:%0x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ALOGD("Added bssid %s", bssidOut); params.ap[i].low = helper.getIntField(objAp, "low"); params.ap[i].high = helper.getIntField(objAp, "high"); } See attached for a POC which causes a crash before the function with the corrupted stack frame returns and checks the stack cookie. LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA [---------------------------------------------------------------------REGISTERS----------------------------------------------------------------------] *X0 0x80000000 <-- 0x0 *X1 0x0 *X2 0x707882c3e0 <-- u'c0:1d:b3:3f:01:...' *X3 0x3 *X4 0x709bf05fc0 <-- stp x28, x27, [sp, #-0x60]! *X5 0x709c1f07b0 (art::gJniNativeInterface) <-- 0x0 *X6 0x709bf27034 <-- cbz x2, #0x709bf27040 /* u'b' */ *X7 0x284801ff284800ff *X8 0xc01d0142c01d0229 *X9 0x1 *X10 0xc01d0142c01d0141 *X11 0x7082dff4e8 <-- 0x41013fb31dc0 X12 0x0 *X13 0x0 *X14 0x0 *X15 0x33511e057221be *X16 0x709f0035a0 (pthread_getspecific@got.plt) --> 0x709efaad5c (pthread_getspecific) <-- movz w8, #0x8000, lsl #16 *X17 0x709efaad5c (pthread_getspecific) <-- movz w8, #0x8000, lsl #16 *X18 0x0 *X19 0x707882c3e0 <-- u'c0:1d:b3:3f:01:...' *X20 0x7082dfe0a0 --> 0x70833c1470 --> 0x7083381c0c (android::JNIObject<_jobject*>::~JNIObject()) <-- adrp x2, #0x70833c2000 *X21 0x7082dfe0b8 --> 0x70833c1490 --> 0x7083381c70 (android::JNIObject<_jstring*>::~JNIObject()) <-- adrp x2, #0x70833c2000 *X22 0x7082dfe078 <-- 0x0 *X23 0xb1da807287fa8cf *X24 0x709f00e86c (je_tsd_tsd) <-- 0xa880000000 *X25 0x7082dfe8d8 <-- u'c0:1d:b3:3f:1:4...' *X26 0x200011 *X27 0x7082dfe0d0 <-- 0x100000000001 *X28 0x707882c3e0 <-- u'c0:1d:b3:3f:01:...' *SP 0x70815310f0 <-- 0x0 *PC 0x709efaada8 (pthread_getspecific+76) <-- ldr x10, [x10, #0xe0] [------------------------------------------------------------------------CODE------------------------------------------------------------------------] => 0x709efaada8L ldr x10, [x10, #0xe0] 0x709efaadacL cmp x10, x9 0x709efaadb0L b.ne #pthread_getspecific+56 <0x709efaad94> ... 0x709efaad94L mov x0, xzr 0x709efaad98L str xzr, [x8] 0x709efaad9cL ret 0x709efaada0L add x10, x10, x8, lsl #4 0x709efaada4L add x8, x10, #0xe8 => 0x709efaada8L ldr x10, [x10, #0xe0] 0x709efaadacL cmp x10, x9 0x709efaadb0L b.ne #pthread_getspecific+56 <0x709efaad94> [------------------------------------------------------------------------CODE------------------------------------------------------------------------] 155 in bionic/libc/bionic/pthread_key.cpp [-----------------------------------------------------------------------STACK------------------------------------------------------------------------] 00:0000| sp 0x70815310f0 <-- 0x0 ... 04:0020| 0x7081531110 --> 0x3f800000 <-- 0x0 05:0028| 0x7081531118 <-- 0x0 ... [---------------------------------------------------------------------BACKTRACE----------------------------------------------------------------------] > f 0 709efaada8 pthread_getspecific+76 f 1 709efd2394 je_free+68 f 2 709efd2394 je_free+68 f 3 709efd2394 je_free+68 f 4 709efd2394 je_free+68 f 5 7083387d10 f 6 7083387d10 f 7 7083387d10 Program received signal SIGSEGV (fault address 0x1d0142c01d0221) pwndbg> bt #0 pthread_getspecific (key=) at bionic/libc/bionic/pthread_key.cpp:160 #1 0x000000709efd2394 in je_tsd_wrapper_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609 #2 je_tsd_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609 #3 je_tsd_fetch () at external/jemalloc/include/jemalloc/internal/tsd.h:614 #4 je_free (ptr=0x707882c3e0) at external/jemalloc/src/jemalloc.c:1932 #5 0x0000007083387d10 in _JNIEnv::ReleaseStringUTFChars (utf=0x707882c3e0 "c0:1d:b3:3f:01:"..., string=0x200011, this=0x7091fd2b00) at libnativehelper/include/nativehelper/jni.h:851 #6 ScopedUtfChars::~ScopedUtfChars (this=, __in_chrg=) at libnativehelper/include/nativehelper/ScopedUtfChars.h:45 #7 android::android_net_wifi_setHotlist (env=0x7091fd2b00, cls=, iface=, id=0x690a3633, ap=) at frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp:799 #8 0x000000709b1a084c in ?? () Fixed in https://source.android.com/security/bulletin/2016-12-01.html Proof of Concept: https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/40945.zip