CVE-2016-6799
Description
Product: Apache Cordova Android 5.2.2 and earlier. The application calls methods of the Log class. Messages passed to these methods (Log.v(), Log.d(), Log.i(), Log.w(), and Log.e()) are stored in a series of circular buffers on the device. By default, a maximum of four 16 KB rotated logs are kept in addition to the current log. The logged data can be read using Logcat on the device. When using platforms prior to Android 4.1 (Jelly Bean), the log data is not sandboxed per application; any application installed on the device has the capability to read data logged by other applications.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
cordova-androidnpm | < 6.0.0 | 6.0.0 |
Affected products
2- Apache Software Foundation/Apache Cordova Androidv5Range: 5.2.2 and earlier
Patches
14a0a7bc424faCordova-Android should use org.apache.cordova.LOG for logging
11 files changed · +97 −95
framework/src/org/apache/cordova/CallbackContext.java+5 −7 modified@@ -20,8 +20,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.json.JSONArray; -import android.util.Log; - import org.apache.cordova.CordovaWebView; import org.apache.cordova.PluginResult; import org.json.JSONObject; @@ -38,23 +36,23 @@ public CallbackContext(String callbackId, CordovaWebView webView) { this.callbackId = callbackId; this.webView = webView; } - + public boolean isFinished() { return finished; } - + public boolean isChangingThreads() { return changingThreads > 0; } - + public String getCallbackId() { return callbackId; } public void sendPluginResult(PluginResult pluginResult) { synchronized (this) { if (finished) { - Log.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage()); + LOG.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage()); return; } else { finished = !pluginResult.getKeepCallback(); @@ -98,7 +96,7 @@ public void success(JSONArray message) { public void success(byte[] message) { sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); } - + /** * Helper for success callbacks that just returns the Status.OK by default *
framework/src/org/apache/cordova/Config.java+1 −2 modified@@ -22,7 +22,6 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.List; import android.app.Activity; -import android.util.Log; @Deprecated // Use Whitelist, CordovaPrefences, etc. directly. public class Config { @@ -61,7 +60,7 @@ public static String getErrorUrl() { public static List<PluginEntry> getPluginEntries() { return parser.getPluginEntries(); } - + public static CordovaPreferences getPreferences() { return parser.getPreferences(); }
framework/src/org/apache/cordova/CordovaActivity.java+10 −7 modified@@ -34,7 +34,6 @@ Licensed to the Apache Software Foundation (ASF) under one import android.media.AudioManager; import android.os.Build; import android.os.Bundle; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -50,7 +49,7 @@ Licensed to the Apache Software Foundation (ASF) under one * html file that contains the application. * * As an example: - * + * * <pre> * package org.apache.cordova.examples; * @@ -67,8 +66,8 @@ Licensed to the Apache Software Foundation (ASF) under one * } * } * </pre> - * - * Cordova xml configuration: Cordova uses a configuration file at + * + * Cordova xml configuration: Cordova uses a configuration file at * res/xml/config.xml to specify its settings. See "The config.xml File" * guide in cordova-docs at http://cordova.apache.org/docs for the documentation * for the configuration. The use of the set*Property() methods is @@ -104,17 +103,21 @@ public class CordovaActivity extends Activity { */ @Override public void onCreate(Bundle savedInstanceState) { + // need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception + loadConfig(); + + String logLevel = preferences.getString("loglevel", "ERROR"); + LOG.setLogLevel(logLevel); + LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting"); LOG.d(TAG, "CordovaActivity.onCreate()"); - // need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception - loadConfig(); if (!preferences.getBoolean("ShowTitle", false)) { getWindow().requestFeature(Window.FEATURE_NO_TITLE); } if (preferences.getBoolean("SetFullscreen", false)) { - Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version."); + LOG.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version."); preferences.set("Fullscreen", true); } if (preferences.getBoolean("Fullscreen", false)) {
framework/src/org/apache/cordova/CordovaBridge.java+7 −9 modified@@ -23,8 +23,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.json.JSONArray; import org.json.JSONException; -import android.util.Log; - /** * Contains APIs that the JS can call. All functions in here should also have * an equivalent entry in CordovaChromeClient.java, and be added to @@ -87,15 +85,15 @@ public String jsRetrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) th private boolean verifySecret(String action, int bridgeSecret) throws IllegalAccessException { if (!jsMessageQueue.isBridgeEnabled()) { if (bridgeSecret == -1) { - Log.d(LOG_TAG, action + " call made before bridge was enabled."); + LOG.d(LOG_TAG, action + " call made before bridge was enabled."); } else { - Log.d(LOG_TAG, "Ignoring " + action + " from previous page load."); + LOG.d(LOG_TAG, "Ignoring " + action + " from previous page load."); } return false; } // Bridge secret wrong and bridge not due to it being from the previous page. if (expectedBridgeSecret < 0 || bridgeSecret != expectedBridgeSecret) { - Log.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!"); + LOG.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!"); clearBridgeSecret(); throw new IllegalAccessException(); } @@ -120,7 +118,7 @@ int generateBridgeSecret() { public void reset() { jsMessageQueue.reset(); - clearBridgeSecret(); + clearBridgeSecret(); } public String promptOnJsPrompt(String origin, String message, String defaultValue) { @@ -141,7 +139,7 @@ public String promptOnJsPrompt(String origin, String message, String defaultValu } return ""; } - // Sets the native->JS bridge mode. + // Sets the native->JS bridge mode. else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) { try { int bridgeSecret = Integer.parseInt(defaultValue.substring(16)); @@ -153,7 +151,7 @@ else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) { } return ""; } - // Polling for JavaScript messages + // Polling for JavaScript messages else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) { int bridgeSecret = Integer.parseInt(defaultValue.substring(9)); try { @@ -175,7 +173,7 @@ else if (defaultValue != null && defaultValue.startsWith("gap_init:")) { int secret = generateBridgeSecret(); return ""+secret; } else { - Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin); + LOG.e(LOG_TAG, "gap_init called from restricted origin: " + origin); } return ""; }
framework/src/org/apache/cordova/CordovaInterfaceImpl.java+2 −3 modified@@ -24,7 +24,6 @@ Licensed to the Apache Software Foundation (ASF) under one import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.util.Log; import android.util.Pair; import org.json.JSONException; @@ -147,13 +146,13 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent intent) activityResultCallback = null; if (callback != null) { - Log.d(TAG, "Sending activity result to plugin"); + LOG.d(TAG, "Sending activity result to plugin"); initCallbackService = null; savedResult = null; callback.onActivityResult(requestCode, resultCode, intent); return true; } - Log.w(TAG, "Got an activity result, but no plugin was registered to receive it" + (savedResult != null ? " yet!" : ".")); + LOG.w(TAG, "Got an activity result, but no plugin was registered to receive it" + (savedResult != null ? " yet!" : ".")); return false; }
framework/src/org/apache/cordova/CordovaWebViewImpl.java+2 −3 modified@@ -21,7 +21,6 @@ Licensed to the Apache Software Foundation (ASF) under one import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.View; @@ -245,7 +244,7 @@ public void showWebPage(String url, boolean openExternal, boolean clearHistory, @Deprecated public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) { // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0 - Log.d(TAG, "showing Custom View"); + LOG.d(TAG, "showing Custom View"); // if a view already exists then immediately terminate the new one if (mCustomView != null) { callback.onCustomViewHidden(); @@ -276,7 +275,7 @@ public void showCustomView(View view, WebChromeClient.CustomViewCallback callbac public void hideCustomView() { // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0 if (mCustomView == null) return; - Log.d(TAG, "Hiding Custom View"); + LOG.d(TAG, "Hiding Custom View"); // Hide the custom view. mCustomView.setVisibility(View.GONE);
framework/src/org/apache/cordova/engine/SystemWebChromeClient.java+13 −14 modified@@ -26,7 +26,6 @@ Licensed to the Apache Software Foundation (ASF) under one import android.content.Intent; import android.net.Uri; import android.os.Build; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup.LayoutParams; @@ -62,7 +61,7 @@ public class SystemWebChromeClient extends WebChromeClient { // the video progress view private View mVideoProgressView; - + private CordovaDialogsHelper dialogsHelper; private Context appContext; @@ -193,7 +192,7 @@ public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) } } - + // API level 7 is required for this, see if we could lower this using something else @Override public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) { @@ -213,9 +212,9 @@ public void onHideCustomView() { */ public View getVideoLoadingProgressView() { - if (mVideoProgressView == null) { + if (mVideoProgressView == null) { // Create a new Loading view programmatically. - + // create the linear layout LinearLayout layout = new LinearLayout(parentEngine.getView().getContext()); layout.setOrientation(LinearLayout.VERTICAL); @@ -226,12 +225,12 @@ public View getVideoLoadingProgressView() { ProgressBar bar = new ProgressBar(parentEngine.getView().getContext()); LinearLayout.LayoutParams barLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); barLayoutParams.gravity = Gravity.CENTER; - bar.setLayoutParams(barLayoutParams); + bar.setLayoutParams(barLayoutParams); layout.addView(bar); - + mVideoProgressView = layout; } - return mVideoProgressView; + return mVideoProgressView; } // <input type=file> support: @@ -240,11 +239,11 @@ public View getVideoLoadingProgressView() { public void openFileChooser(ValueCallback<Uri> uploadMsg) { this.openFileChooser(uploadMsg, "*/*"); } - + public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) { this.openFileChooser(uploadMsg, acceptType, null); } - + public void openFileChooser(final ValueCallback<Uri> uploadMsg, String acceptType, String capture) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); @@ -254,7 +253,7 @@ public void openFileChooser(final ValueCallback<Uri> uploadMsg, String acceptTyp @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); - Log.d(LOG_TAG, "Receive file chooser URL: " + result); + LOG.d(LOG_TAG, "Receive file chooser URL: " + result); uploadMsg.onReceiveValue(result); } }, intent, FILECHOOSER_RESULTCODE); @@ -269,12 +268,12 @@ public boolean onShowFileChooser(WebView webView, final ValueCallback<Uri[]> fil @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent); - Log.d(LOG_TAG, "Receive file chooser URL: " + result); + LOG.d(LOG_TAG, "Receive file chooser URL: " + result); filePathsCallback.onReceiveValue(result); } }, intent, FILECHOOSER_RESULTCODE); } catch (ActivityNotFoundException e) { - Log.w("No activity found to handle file chooser intent.", e); + LOG.w("No activity found to handle file chooser intent.", e); filePathsCallback.onReceiveValue(null); } return true; @@ -283,7 +282,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onPermissionRequest(final PermissionRequest request) { - Log.d(LOG_TAG, "onPermissionRequest: " + Arrays.toString(request.getResources())); + LOG.d(LOG_TAG, "onPermissionRequest: " + Arrays.toString(request.getResources())); request.grant(request.getResources()); }
framework/src/org/apache/cordova/engine/SystemWebViewEngine.java+19 −19 modified@@ -27,7 +27,6 @@ Licensed to the Apache Software Foundation (ASF) under one import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.os.Build; -import android.util.Log; import android.view.View; import android.webkit.WebSettings; import android.webkit.WebSettings.LayoutAlgorithm; @@ -40,6 +39,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaWebViewEngine; import org.apache.cordova.ICordovaCookieManager; +import org.apache.cordova.LOG; import org.apache.cordova.NativeToJsMessageQueue; import org.apache.cordova.PluginManager; @@ -145,32 +145,32 @@ private void initWebViewSettings() { settings.setJavaScriptEnabled(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL); - + // Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2) try { Method gingerbread_getMethod = WebSettings.class.getMethod("setNavDump", new Class[] { boolean.class }); - + String manufacturer = android.os.Build.MANUFACTURER; - Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer); + LOG.d(TAG, "CordovaWebView is running on device made by: " + manufacturer); if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB && android.os.Build.MANUFACTURER.contains("HTC")) { gingerbread_getMethod.invoke(settings, true); } } catch (NoSuchMethodException e) { - Log.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8"); + LOG.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8"); } catch (IllegalArgumentException e) { - Log.d(TAG, "Doing the NavDump failed with bad arguments"); + LOG.d(TAG, "Doing the NavDump failed with bad arguments"); } catch (IllegalAccessException e) { - Log.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore"); + LOG.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore"); } catch (InvocationTargetException e) { - Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore."); + LOG.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore."); } //We don't save any form data in the application settings.setSaveFormData(false); settings.setSavePassword(false); - + // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist // while we do this if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { @@ -184,29 +184,29 @@ private void initWebViewSettings() { String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); settings.setDatabaseEnabled(true); settings.setDatabasePath(databasePath); - - + + //Determine whether we're in debug or release mode, and turn on Debugging! ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo(); if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { enableRemoteDebugging(); } - + settings.setGeolocationDatabasePath(databasePath); // Enable DOM storage settings.setDomStorageEnabled(true); // Enable built-in geolocation settings.setGeolocationEnabled(true); - + // Enable AppCache // Fix for CB-2282 settings.setAppCacheMaxSize(5 * 1048576); settings.setAppCachePath(databasePath); settings.setAppCacheEnabled(true); - + // Fix for CB-1405 // Google issue 4641 String defaultUserAgent = settings.getUserAgentString(); @@ -222,7 +222,7 @@ private void initWebViewSettings() { } } // End CB-3360 - + IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); if (this.receiver == null) { @@ -242,18 +242,18 @@ private void enableRemoteDebugging() { try { WebView.setWebContentsDebuggingEnabled(true); } catch (IllegalArgumentException e) { - Log.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! "); + LOG.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! "); e.printStackTrace(); } } private static void exposeJsInterface(WebView webView, CordovaBridge bridge) { if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) { - Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old."); + LOG.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old."); // Bug being that Java Strings do not get converted to JS strings automatically. // This isn't hard to work-around on the JS side, but it's easier to just // use the prompt bridge instead. - return; + return; } SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge); webView.addJavascriptInterface(exposedJsApi, "_cordovaNative"); @@ -327,7 +327,7 @@ public void destroy() { try { webView.getContext().unregisterReceiver(receiver); } catch (Exception e) { - Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e); + LOG.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e); } } }
framework/src/org/apache/cordova/LOG.java+10 −0 modified@@ -154,6 +154,16 @@ public static void i(String tag, String s, Throwable e) { if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e); } + /** + * Warning log message. + * + * @param tag + * @param e + */ + public static void w(String tag, Throwable e) { + if (LOG.WARN >= LOGLEVEL) Log.w(tag, e); + } + /** * Warning log message. *
framework/src/org/apache/cordova/NativeToJsMessageQueue.java+22 −24 modified@@ -21,8 +21,6 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.ArrayList; import java.util.LinkedList; -import android.util.Log; - /** * Holds the list of messages to be sent to the WebView. */ @@ -42,13 +40,13 @@ public class NativeToJsMessageQueue { // This currently only chops up on message boundaries. It may be useful // to allow it to break up messages. private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240; - + /** * When true, the active listener is not fired upon enqueue. When set to false, - * the active listener will be fired if the queue is non-empty. + * the active listener will be fired if the queue is non-empty. */ private boolean paused; - + /** * The list of JavaScript statements to be sent to JavaScript. */ @@ -58,7 +56,7 @@ public class NativeToJsMessageQueue { * The array of listeners that can be used to send messages to JS. */ private ArrayList<BridgeMode> bridgeModes = new ArrayList<BridgeMode>(); - + /** * When null, the bridge is disabled. This occurs during page transitions. * When disabled, all callbacks are dropped since they are assumed to be @@ -83,11 +81,11 @@ public boolean isEmpty() { */ public void setBridgeMode(int value) { if (value < -1 || value >= bridgeModes.size()) { - Log.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value); + LOG.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value); } else { BridgeMode newMode = value < 0 ? null : bridgeModes.get(value); if (newMode != activeBridgeMode) { - Log.d(LOG_TAG, "Set native->JS mode to " + (newMode == null ? "null" : newMode.getClass().getSimpleName())); + LOG.d(LOG_TAG, "Set native->JS mode to " + (newMode == null ? "null" : newMode.getClass().getSimpleName())); synchronized (this) { activeBridgeMode = newMode; if (newMode != null) { @@ -100,7 +98,7 @@ public void setBridgeMode(int value) { } } } - + /** * Clears all messages and resets to the default bridge mode. */ @@ -114,16 +112,16 @@ public void reset() { private int calculatePackedMessageLength(JsMessage message) { int messageLen = message.calculateEncodedLength(); String messageLenStr = String.valueOf(messageLen); - return messageLenStr.length() + messageLen + 1; + return messageLenStr.length() + messageLen + 1; } - + private void packMessage(JsMessage message, StringBuilder sb) { int len = message.calculateEncodedLength(); sb.append(len) .append(' '); message.encodeAsMessage(sb); } - + /** * Combines and returns queued messages combined into a single string. * Combines as many messages as possible, while staying under MAX_PAYLOAD_SIZE. @@ -154,7 +152,7 @@ public String popAndEncode(boolean fromOnlineEvent) { JsMessage message = queue.removeFirst(); packMessage(message, sb); } - + if (!queue.isEmpty()) { // Attach a char to indicate that there are more messages pending. sb.append('*'); @@ -163,7 +161,7 @@ public String popAndEncode(boolean fromOnlineEvent) { return ret; } } - + /** * Same as popAndEncode(), except encodes in a form that can be executed as JS. */ @@ -185,7 +183,7 @@ public String popAndEncodeAsJs() { } boolean willSendAllMessages = numMessagesToSend == queue.size(); StringBuilder sb = new StringBuilder(totalPayloadLen + (willSendAllMessages ? 0 : 100)); - // Wrap each statement in a try/finally so that if one throws it does + // Wrap each statement in a try/finally so that if one throws it does // not affect the next. for (int i = 0; i < numMessagesToSend; ++i) { JsMessage message = queue.removeFirst(); @@ -206,7 +204,7 @@ public String popAndEncodeAsJs() { String ret = sb.toString(); return ret; } - } + } /** * Add a JavaScript statement to the list. @@ -220,7 +218,7 @@ public void addJavaScript(String statement) { */ public void addPluginResult(PluginResult result, String callbackId) { if (callbackId == null) { - Log.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable()); + LOG.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable()); return; } // Don't send anything if there is no result and there is no need to @@ -243,7 +241,7 @@ public void addPluginResult(PluginResult result, String callbackId) { private void enqueueMessage(JsMessage message) { synchronized (this) { if (activeBridgeMode == null) { - Log.d(LOG_TAG, "Dropping Native->JS message due to disabled bridge"); + LOG.d(LOG_TAG, "Dropping Native->JS message due to disabled bridge"); return; } queue.add(message); @@ -257,15 +255,15 @@ public void setPaused(boolean value) { if (paused && value) { // This should never happen. If a use-case for it comes up, we should // change pause to be a counter. - Log.e(LOG_TAG, "nested call to setPaused detected.", new Throwable()); + LOG.e(LOG_TAG, "nested call to setPaused detected.", new Throwable()); } paused = value; if (!value) { synchronized (this) { if (!queue.isEmpty() && activeBridgeMode != null) { activeBridgeMode.onNativeToJsMessageAvailable(this); } - } + } } } @@ -368,7 +366,7 @@ private static class JsMessage { jsPayloadOrCallbackId = callbackId; this.pluginResult = pluginResult; } - + static int calculateEncodedLengthHelper(PluginResult pluginResult) { switch (pluginResult.getMessageType()) { case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t @@ -395,7 +393,7 @@ static int calculateEncodedLengthHelper(PluginResult pluginResult) { return pluginResult.getMessage().length(); } } - + int calculateEncodedLength() { if (pluginResult == null) { return jsPayloadOrCallbackId.length() + 1; @@ -424,7 +422,7 @@ static void encodeAsMessageHelper(StringBuilder sb, PluginResult pluginResult) { case PluginResult.MESSAGE_TYPE_BINARYSTRING: // S sb.append('S'); sb.append(pluginResult.getMessage()); - break; + break; case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: // A sb.append('A'); sb.append(pluginResult.getMessage()); @@ -443,7 +441,7 @@ static void encodeAsMessageHelper(StringBuilder sb, PluginResult pluginResult) { sb.append(pluginResult.getMessage()); // [ or { } } - + void encodeAsMessage(StringBuilder sb) { if (pluginResult == null) { sb.append('J')
framework/src/org/apache/cordova/PluginManager.java+6 −7 modified@@ -28,7 +28,6 @@ Licensed to the Apache Software Foundation (ASF) under one import android.net.Uri; import android.os.Bundle; import android.os.Debug; -import android.util.Log; /** * PluginManager is exposed to JavaScript in the Cordova WebView. @@ -122,7 +121,7 @@ private void startupPlugins() { public void exec(final String service, final String action, final String callbackId, final String rawArgs) { CordovaPlugin plugin = getPlugin(service); if (plugin == null) { - Log.d(TAG, "exec() call to unknown plugin: " + service); + LOG.d(TAG, "exec() call to unknown plugin: " + service); PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION); app.sendPluginResult(cr, callbackId); return; @@ -134,7 +133,7 @@ public void exec(final String service, final String action, final String callbac long duration = System.currentTimeMillis() - pluginStartTime; if (duration > SLOW_EXEC_WARNING_THRESHOLD) { - Log.w(TAG, "THREAD WARNING: exec() call to " + service + "." + action + " blocked the main thread for " + duration + "ms. Plugin should use CordovaInterface.getThreadPool()."); + LOG.w(TAG, "THREAD WARNING: exec() call to " + service + "." + action + " blocked the main thread for " + duration + "ms. Plugin should use CordovaInterface.getThreadPool()."); } if (!wasValidAction) { PluginResult cr = new PluginResult(PluginResult.Status.INVALID_ACTION); @@ -144,7 +143,7 @@ public void exec(final String service, final String action, final String callbac PluginResult cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION); callbackContext.sendPluginResult(cr); } catch (Exception e) { - Log.e(TAG, "Uncaught exception from plugin", e); + LOG.e(TAG, "Uncaught exception from plugin", e); callbackContext.error(e.getMessage()); } } @@ -222,9 +221,9 @@ public void onPause(boolean multitasking) { * @param handler The HttpAuthHandler used to set the WebView's response * @param host The host requiring authentication * @param realm The realm for which authentication is required - * + * * @return Returns True if there is a plugin which will resolve this auth challenge, otherwise False - * + * */ public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) { for (CordovaPlugin plugin : this.pluginMap.values()) { @@ -234,7 +233,7 @@ public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHa } return false; } - + /** * Called when he system received an SSL client certificate request. Plugin can use * the supplied ClientCertRequest to process this certificate challenge.
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
9- www.securityfocus.com/bid/98365nvdThird Party AdvisoryVDB EntryWEB
- github.com/advisories/GHSA-gwpf-62xp-vrg6ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-6799ghsaADVISORY
- cve.mitre.org/cgi-bin/cvename.cgighsaWEB
- github.com/apache/cordova-android/commit/4a0a7bc424fae14c9689f4a8a2dc250ae3a47f82ghsaWEB
- lists.apache.org/thread.html/1f3e7b0319d64b455f73616f572acee36fbca31f87f5b2e509c45b69@%3Cdev.cordova.apache.org%3EghsaWEB
- snyk.io/vuln/SNYK-JS-CORDOVAANDROID-174935ghsaWEB
- www.npmjs.com/advisories/964ghsaWEB
- lists.apache.org/thread.html/1f3e7b0319d64b455f73616f572acee36fbca31f87f5b2e509c45b69%40%3Cdev.cordova.apache.org%3Envd
News mentions
0No linked articles in our index yet.