Commit message: None
CVE: CVE-2016-3837
CWE: CWE-200
Vulnerability description: service/jni/com_android_server_wifi_WifiNative.cpp in Wi-Fi in Android 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-08-01 allows attackers to obtain sensitive information via a crafted application that provides a MAC address with too few characters, aka internal bug 28164077.

Project: Android

static jobject android_net_wifi_getLinkLayerStats (JNIEnv *env, jclass cls, jint iface) {

 JNIHelper helper(env);
    wifi_stats_result_handler handler;
    memset(&handler, 0, sizeof(handler));
    handler.on_link_stats_results = &onLinkStatsResults;
    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
 int result = hal_fn.wifi_get_link_stats(0, handle, handler);
 if (result < 0) {
        ALOGE("android_net_wifi_getLinkLayerStats: failed to get link statistics\n");
 return NULL;
 }

 JNIObject<jobject> wifiLinkLayerStats = helper.createObject(
 "android/net/wifi/WifiLinkLayerStats");
 if (wifiLinkLayerStats == NULL) {
       ALOGE("Error in allocating wifiLinkLayerStats");
 return NULL;
 }

    helper.setIntField(wifiLinkLayerStats, "beacon_rx", link_stat.beacon_rx);
    helper.setIntField(wifiLinkLayerStats, "rssi_mgmt", link_stat.rssi_mgmt);
    helper.setLongField(wifiLinkLayerStats, "rxmpdu_be", link_stat.ac[WIFI_AC_BE].rx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "rxmpdu_bk", link_stat.ac[WIFI_AC_BK].rx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "rxmpdu_vi", link_stat.ac[WIFI_AC_VI].rx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "rxmpdu_vo", link_stat.ac[WIFI_AC_VO].rx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "txmpdu_be", link_stat.ac[WIFI_AC_BE].tx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "txmpdu_bk", link_stat.ac[WIFI_AC_BK].tx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "txmpdu_vi", link_stat.ac[WIFI_AC_VI].tx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "txmpdu_vo", link_stat.ac[WIFI_AC_VO].tx_mpdu);
    helper.setLongField(wifiLinkLayerStats, "lostmpdu_be", link_stat.ac[WIFI_AC_BE].mpdu_lost);
    helper.setLongField(wifiLinkLayerStats, "lostmpdu_bk", link_stat.ac[WIFI_AC_BK].mpdu_lost);
    helper.setLongField(wifiLinkLayerStats, "lostmpdu_vi",  link_stat.ac[WIFI_AC_VI].mpdu_lost);
    helper.setLongField(wifiLinkLayerStats, "lostmpdu_vo", link_stat.ac[WIFI_AC_VO].mpdu_lost);
    helper.setLongField(wifiLinkLayerStats, "retries_be", link_stat.ac[WIFI_AC_BE].retries);
    helper.setLongField(wifiLinkLayerStats, "retries_bk", link_stat.ac[WIFI_AC_BK].retries);
    helper.setLongField(wifiLinkLayerStats, "retries_vi", link_stat.ac[WIFI_AC_VI].retries);
    helper.setLongField(wifiLinkLayerStats, "retries_vo", link_stat.ac[WIFI_AC_VO].retries);

    helper.setIntField(wifiLinkLayerStats, "on_time", radio_stat.on_time);
    helper.setIntField(wifiLinkLayerStats, "tx_time", radio_stat.tx_time);
    helper.setIntField(wifiLinkLayerStats, "rx_time", radio_stat.rx_time);
    helper.setIntField(wifiLinkLayerStats, "on_time_scan", radio_stat.on_time_scan);

 return wifiLinkLayerStats.detach();
}

Project: Android

static jobject android_net_wifi_getScanResults(
 JNIEnv *env, jclass cls, jint iface, jboolean flush) {

 JNIHelper helper(env);
    wifi_cached_scan_results scan_data[64];
 int num_scan_data = 64;

    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);

    byte b = flush ? 0xFF : 0;
 int result = hal_fn.wifi_get_cached_gscan_results(handle, b, num_scan_data, scan_data, &num_scan_data);
 if (result == WIFI_SUCCESS) {
 JNIObject<jobjectArray> scanData = helper.createObjectArray(
 "android/net/wifi/WifiScanner$ScanData", num_scan_data);
 if (scanData == NULL) {
            ALOGE("Error in allocating array of scanData");
 return NULL;
 }

 for (int i = 0; i < num_scan_data; i++) {

 JNIObject<jobject> data = helper.createObject("android/net/wifi/WifiScanner$ScanData");
 if (data == NULL) {
                ALOGE("Error in allocating scanData");
 return NULL;
 }

            helper.setIntField(data, "mId", scan_data[i].scan_id);
            helper.setIntField(data, "mFlags", scan_data[i].flags);

 /* sort all scan results by timestamp */
            qsort(scan_data[i].results, scan_data[i].num_results,
 sizeof(wifi_scan_result), compare_scan_result_timestamp);

 JNIObject<jobjectArray> scanResults = helper.createObjectArray(
 "android/net/wifi/ScanResult", scan_data[i].num_results);
 if (scanResults == NULL) {
                ALOGE("Error in allocating scanResult array");
 return NULL;
 }

            wifi_scan_result *results = scan_data[i].results;
 for (int j = 0; j < scan_data[i].num_results; j++) {

 JNIObject<jobject> scanResult = createScanResult(helper, &results[j]);
 if (scanResult == NULL) {
                    ALOGE("Error in creating scan result");
 return NULL;
 }

                helper.setObjectArrayElement(scanResults, j, scanResult);
 }

            helper.setObjectField(data, "mResults", "[Landroid/net/wifi/ScanResult;", scanResults);
            helper.setObjectArrayElement(scanData, i, data);
 }

 return scanData.detach();
 } else {
 return NULL;
 }
}

Project: Android

static jintArray android_net_wifi_getValidChannels(JNIEnv *env, jclass cls,
        jint iface, jint band) {

 JNIHelper helper(env);
    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
    ALOGD("getting valid channels %p", handle);

 static const int MaxChannels = 64;
    wifi_channel channels[64];
 int num_channels = 0;
    wifi_error result = hal_fn.wifi_get_valid_channels(handle, band, MaxChannels,
            channels, &num_channels);

 if (result == WIFI_SUCCESS) {
 JNIObject<jintArray> channelArray = helper.newIntArray(num_channels);
 if (channelArray == NULL) {
            ALOGE("failed to allocate channel list");
 return NULL;
 }

        helper.setIntArrayRegion(channelArray, 0, num_channels, channels);
 return channelArray.detach();
 } else {
        ALOGE("failed to get channel list : %d", result);
 return NULL;
 }
}

Project: Android

static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
{
 return (::wifi_load_driver() == 0);
}

Project: Android

static jboolean android_net_wifi_setBssidBlacklist(
 JNIEnv *env, jclass cls, jint iface, jint id, jobject list) {

 JNIHelper helper(env);
    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
    ALOGD("configure BSSID black list request [%d] = %p", id, handle);

    wifi_bssid_params params;
    memset(&params, 0, sizeof(params));

 if (list != NULL) {
 size_t len = helper.getArrayLength((jobjectArray)list);
 if (len > (size_t)MAX_BLACKLIST_BSSID) {
 return false;
 }
 for (unsigned int i = 0; i < len; i++) {

 JNIObject<jobject> jbssid = helper.getObjectArrayElement(list, i);
 if (jbssid == NULL) {
                ALOGD("configure BSSID blacklist: could not get element %d", i);
 continue;
 }

 ScopedUtfChars chars(env, (jstring)jbssid.get());
 const char *bssid = chars.c_str();
 if (bssid == NULL) {
                ALOGE("Error getting bssid");
 return false;
 }

            mac_addr addr;
            parseMacAddress(bssid, addr);
            memcpy(params.bssids[i], addr, sizeof(mac_addr));

 char bssidOut[32];
            sprintf(bssidOut, "%0x:%0x:%0x:%0x:%0x:%0x", addr[0], addr[1],
                addr[2], addr[3], addr[4], addr[5]);

            ALOGD("BSSID blacklist: added bssid %s", bssidOut);

            params.num_bssid++;
 }
 }

    ALOGD("Added %d bssids", params.num_bssid);
 return hal_fn.wifi_set_bssid_blacklist(id, handle, params) == WIFI_SUCCESS;
}

Project: Android

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(&params, 0, sizeof(params));

    params.lost_ap_sample_size = helper.getIntField(ap, "apLostThreshold");

 JNIObject<jobjectArray> array = helper.getArrayField(
            ap, "bssidInfos", "[Landroid/net/wifi/WifiScanner$BssidInfo;");
    params.num_bssid = helper.getArrayLength(array);

 if (params.num_bssid == 0) {
        ALOGE("Error in accesing array");
 return false;
 }

 for (int i = 0; i < params.num_bssid; i++) {
 JNIObject<jobject> objAp = helper.getObjectArrayElement(array, i);

 JNIObject<jstring> 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);

        mac_addr addr;
        memcpy(addr, params.ap[i].bssid, sizeof(mac_addr));

 char bssidOut[32];
        sprintf(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");
 }

    wifi_hotlist_ap_found_handler handler;
    memset(&handler, 0, sizeof(handler));

    handler.on_hotlist_ap_found = &onHotlistApFound;
    handler.on_hotlist_ap_lost  = &onHotlistApLost;
 return hal_fn.wifi_set_bssid_hotlist(id, handle, params, handler) == WIFI_SUCCESS;
}

Project: Android

static void android_net_wifi_setLinkLayerStats (JNIEnv *env, jclass cls, jint iface, int enable) {
 JNIHelper helper(env);
    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);

    wifi_link_layer_params params;
    params.aggressive_statistics_gathering = enable;
    params.mpdu_size_threshold = 128;

    ALOGD("android_net_wifi_setLinkLayerStats: %u\n", enable);

    hal_fn.wifi_set_link_stats(handle, params);
}

Project: Android

static jint android_net_wifi_start_rssi_monitoring_native(JNIEnv *env, jclass cls, jint iface,
        jint idx, jbyte maxRssi, jbyte minRssi) {

 JNIHelper helper(env);
    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
    ALOGD("Start Rssi monitoring = %p", handle);
    ALOGD("MinRssi %d MaxRssi %d", minRssi, maxRssi);
    wifi_error ret;
    wifi_request_id id = idx;
    wifi_rssi_event_handler eh;
    eh.on_rssi_threshold_breached = onRssiThresholdbreached;
    ret = hal_fn.wifi_start_rssi_monitoring(id, handle, maxRssi, minRssi, eh);
 return ret;
}

Project: Android

static jint android_net_wifi_stop_rssi_monitoring_native(JNIEnv *env, jclass cls,
        jint iface, jint idx) {
 JNIHelper helper(env);
    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
    ALOGD("Stop Rssi monitoring = %p", handle);
    wifi_error ret;
    wifi_request_id id = idx;
    ret = hal_fn.wifi_stop_rssi_monitoring(id, handle);
 return ret;
}

Project: Android

static void on_tdls_state_changed(mac_addr addr, wifi_tdls_status status) {

 JNIHelper helper(mVM);

    ALOGD("on_tdls_state_changed is called: vm = %p, obj = %p", mVM, mCls);

 char mac[32];
    sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4],
            addr[5]);

 JNIObject<jstring> mac_address = helper.newStringUTF(mac);
    helper.reportEvent(mCls, "onTdlsStatus", "(Ljava/lang/StringII;)V",
        mac_address.get(), status.state, status.reason);

}

Project: Android

 static void parseMacAddress(const char *str, mac_addr addr) {
    addr[0] = parseHexByte(str);
    addr[1] = parseHexByte(str);
    addr[2] = parseHexByte(str);
    addr[3] = parseHexByte(str);
    addr[4] = parseHexByte(str);
    addr[5] = parseHexByte(str);
}