CVE-2022-4903 (published 2023-02-10T15:15Z)

A vulnerability was found in CodenameOne 7.0.70. It has been classified as problematic. Affected is an unknown function. The manipulation leads to use of implicit intent for sensitive communication. It is possible to launch the attack remotely. The complexity of an attack is rather high. The exploitability is told to be difficult. Upgrading to version 7.0.71 is able to address this issue. The patch is identified as dad49c9ef26a598619fc48d2697151a02987d478. It is recommended to upgrade the affected component. VDB-220470 is the identifier assigned to this vulnerability.

CVSS v3 base score: 8.1, HIGH (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-668
cwe_name: Exposure of Resource to Wrong Sphere
description: The product exposes a resource to the wrong control sphere, providing unintended actors with inappropriate access to the resource.
extended_description: 
            Resources such as files and directories may be inadvertently exposed through mechanisms such as insecure permissions, or when a program accidentally operates on the wrong object. For example, a program may intend that private files can only be provided to a specific user. This effectively defines a control sphere that is intended to prevent attackers from accessing these private files. If the file permissions are insecure, then parties other than the user will be able to access those files.
            A separate control sphere might effectively require that the user can only access the private files, but not any other files on the system. If the program does not ensure that the user is only requesting private files, then the user might be able to access other files on the system.
            In either case, the end result is that a resource has been exposed to the wrong party.
         
         

Fix information:
repo_url: https://github.com/codenameone/CodenameOne
commit_details: repo_url: https://github.com/codenameone/CodenameOne
author: Shai Almog
author_date: 2022-04-23 07:50:21+03:00
msg: Fixed #3583 Pending Intent vulnerability
repository: repo_url: https://github.com/codenameone/CodenameOne
repo_name: codenameone/CodenameOne
description: Cross-platform framework for building truly native mobile apps with Java or Kotlin. Write Once Run Anywhere support for iOS, Android, Desktop & Web.
repo_language: Java
owner: codenameone
file_changes: filename: AndroidImplementation.java
change_type: ModificationType.MODIFY
diff: @@ -775,7 +775,36 @@ public class AndroidImplementation extends CodenameOneImplementation implements
         }
         return out.toArray(new PushActionCategory[out.size()]);
     }
-    
+
+    public static PendingIntent createPendingIntent(Context ctx, int value, Intent intent) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            // PendingIntent.FLAG_IMMUTABLE
+            return PendingIntent.getActivity(ctx, value, newIntent, 67108864);
+        } else {
+            return PendingIntent.getActivity(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+        }
+    }
+
+    public static PendingIntent getPendingIntent(Context ctx, int value, Intent intent) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            // PendingIntent.FLAG_IMMUTABLE
+            return PendingIntent.getService(ctx, value, newIntent, 67108864);
+        } else {
+            return PendingIntent.getService(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+        }
+        PendingIntent.getService
+    }
+
+    public static PendingIntent getBroadcastPendingIntent(Context ctx, int value, Intent intent) {
+        if (android.os.Build.VERSION.SDK_INT >= 23) {
+            // PendingIntent.FLAG_IMMUTABLE
+            return PendingIntent.getBroadcast(ctx, value, newIntent, 67108864);
+        } else {
+            return PendingIntent.getBroadcast(ctx, value, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+        }
+        PendingIntent.getService
+    }
+
     /**
      * Adds actions to a push notification.  This is called by the Push broadcast receiver probably before 
      * Codename One is initialized
@@ -811,7 +840,7 @@ public class AndroidImplementation extends CodenameOneImplementation implements
         for (PushAction action : category.getActions()) {
             Intent newIntent = (Intent)targetIntent.clone();
             newIntent.putExtra("pushActionId", action.getId());
-            PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode++, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+            PendingIntent contentIntent = createPendingIntent(context, requestCode++, newIntent);
             try {
                 int iconId = 0;
                 try { iconId = Integer.parseInt(action.getIcon());} catch (Exception ex){}
@@ -7093,7 +7122,7 @@ public class AndroidImplementation extends CodenameOneImplementation implements
 
         Intent notificationIntent = new Intent();
         notificationIntent.setComponent(activityComponentName);
-        PendingIntent contentIntent = PendingIntent.getActivity(getContext(), 0, notificationIntent, 0);
+        PendingIntent contentIntent = createPendingIntent(getContext(), 0, notificationIntent);
 
 
         NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext())
@@ -10416,20 +10445,19 @@ public class AndroidImplementation extends CodenameOneImplementation implements
             //intent.putExtra("backgroundClass", getBackgroundLocationListener().getName());
             //an ugly workaround to the putExtra bug 
             intent.setData(Uri.parse("http://codenameone.com/a?" + getBackgroundFetchListener().getClass().getName()));
-            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                    intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = getPendingIntent(context, 0,
+                    intent);
             notificationIntent.putExtra(LocalNotificationPublisher.BACKGROUND_FETCH_INTENT, pendingIntent);
 
         } else {
             contentIntent.setData(Uri.parse("http://codenameone.com/a?LocalNotificationID="+Uri.encode(notif.getId())));
         }
-        PendingIntent pendingContentIntent = PendingIntent.getActivity(getContext(), 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntent pendingContentIntent = createPendingIntent(getContext(), 0, contentIntent);
 
         notificationIntent.putExtra(LocalNotificationPublisher.NOTIFICATION_INTENT, pendingContentIntent);
 
 
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntent pendingIntent = getBroadcastPendingIntent(getContext(), 0, notificationIntent);
 
         AlarmManager alarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
         if (BACKGROUND_FETCH_NOTIFICATION_ID.equals(notif.getId())) {
@@ -10462,7 +10490,7 @@ public class AndroidImplementation extends CodenameOneImplementation implements
         Intent notificationIntent = new Intent(getContext(), LocalNotificationPublisher.class);
         notificationIntent.setAction(getContext().getApplicationInfo().packageName + "." + notificationId);
 
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntent pendingIntent = getBroadcastPendingIntent(getContext(), 0, notificationIntent);
         AlarmManager alarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
         alarmManager.cancel(pendingIntent);
     }

programming_language: Java
filename: CodenameOneActivity.java
change_type: ModificationType.MODIFY
diff: @@ -428,7 +428,7 @@ public class CodenameOneActivity extends Activity {
     public void registerForPush(String key) {
         Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
         registrationIntent.setPackage("com.google.android.gms");
-        registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); // boilerplate
+        registrationIntent.putExtra("app", AndroidImplementation.getBroadcastPendingIntent(this, 0, new Intent())); // boilerplate
         registrationIntent.putExtra("sender", key);
         startService(registrationIntent);
     }
@@ -436,7 +436,7 @@ public class CodenameOneActivity extends Activity {
     public void stopReceivingPush() {
         Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
         unregIntent.setPackage("com.google.android.gms");
-        unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
+        unregIntent.putExtra("app", AndroidImplementation.getBroadcastPendingIntent(this, 0, new Intent()));
         startService(unregIntent);
     }
 

programming_language: Java
filename: PushNotificationService.java
change_type: ModificationType.MODIFY
diff: @@ -103,7 +103,8 @@ public abstract class PushNotificationService extends Service implements PushCal
     
     public abstract PushCallback getPushCallbackInstance();
     public abstract Class getStubClass();
-    
+
+
     @Override
     public void push(final String value) {
         final PushCallback callback = getPushCallbackInstance();
@@ -116,7 +117,7 @@ public abstract class PushNotificationService extends Service implements PushCal
         } else {
             NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
             Intent newIntent = new Intent(this, getStubClass());
-            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+            PendingIntent contentIntent = AndroidImplementation.createPendingIntent(this, 0, newIntent);
 
 
 

programming_language: Java
filename: AndroidLocationPlayServiceManager.java
change_type: ModificationType.MODIFY
diff: @@ -189,9 +189,8 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
                             if (bgListenerClass != null) {
                                 intent.setData(Uri.parse("http://codenameone.com/a?" + bgListenerClass.getName()));
                             }
-                            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                                    intent,
-                                    PendingIntent.FLAG_UPDATE_CURRENT);
+                            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                                    intent);
                             inMemoryBackgroundLocationListener = AndroidLocationPlayServiceManager.this;
 
 
@@ -228,16 +227,15 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
             Intent intent = new Intent(context, BackgroundLocationBroadcastReceiver.class);
             intent.setData(Uri.parse("http://codenameone.com/a?" + bgListenerClass.getName()));
             intent.setAction(BackgroundLocationBroadcastReceiver.ACTION_PROCESS_UPDATES);
-            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = AndroidImplementation.getBroadcastPendingIntent(context, 0, intent);
             return pendingIntent;
         } else {
 
 
             Intent intent = new Intent(context, BackgroundLocationHandler.class);
             intent.setData(Uri.parse("http://codenameone.com/a?" + bgListenerClass.getName()));
-            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                    intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                    intent);
             return pendingIntent;
         }
     }
@@ -290,9 +288,8 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
                             if (bgListenerClass != null) {
                                 intent.putExtra("backgroundClass", bgListenerClass.getName());
                             }
-                            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                                    intent,
-                                    PendingIntent.FLAG_UPDATE_CURRENT);
+                            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                                    intent);
 
                             //LocationServices.FusedLocationApi.removeLocationUpdates(getmGoogleApiClient(), pendingIntent);
                             removeLocationUpdates(context, pendingIntent);
@@ -481,16 +478,15 @@ public class AndroidLocationPlayServiceManager extends com.codename1.location.Lo
             intent.setAction(BackgroundLocationBroadcastReceiver.ACTION_PROCESS_GEOFENCE_TRANSITIONS);
             intent.setData(Uri.parse("http://codenameone.com/a?" + geofenceListenerClass.getName()));
             //intent.setAction(BackgroundLocationBroadcastReceiver.ACTION_PROCESS_GEOFENCE_TRANSITIONS);
-            geofencePendingIntent = PendingIntent.getBroadcast(AndroidNativeUtil.getContext().getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+            geofencePendingIntent = AndroidImplementation.getBroadcastPendingIntent(AndroidNativeUtil.getContext().getApplicationContext(), 0, intent);
             return geofencePendingIntent;
         } else {
 
             Intent intent = new Intent(context, GeofenceHandler.class);
             intent.putExtra("geofenceClass", geofenceListenerClass.getName());
             intent.putExtra("geofenceID", gf.getId());
-            PendingIntent pendingIntent = PendingIntent.getService(context, 0,
-                    intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent pendingIntent = AndroidImplementation.getPendingIntent(context, 0,
+                    intent);
 
 
             return pendingIntent;

programming_language: Java
filename: BackgroundAudioService.java
change_type: ModificationType.MODIFY
diff: @@ -53,6 +53,7 @@ import android.support.v4.media.session.PlaybackStateCompat;
 
 import android.text.TextUtils;
 
+import com.codename1.impl.android.AndroidImplementation;
 import com.codename1.ui.Display;
 
 
@@ -267,9 +268,6 @@ public class BackgroundAudioService extends MediaBrowserServiceCompat implements
     }
 
 
-
-
-
     private void initMediaSession() {
         ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
         mMediaSessionCompat = new MediaSessionCompat(getApplicationContext(), "Tag", mediaButtonReceiver, null);
@@ -279,7 +277,7 @@ public class BackgroundAudioService extends MediaBrowserServiceCompat implements
 
         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         mediaButtonIntent.setClass(this, MediaButtonReceiver.class);
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
+        PendingIntent pendingIntent = AndroidImplementation.getBroadcastPendingIntent(this, 0, mediaButtonIntent);
         mMediaSessionCompat.setMediaButtonReceiver(pendingIntent);
 
         setSessionToken(mMediaSessionCompat.getSessionToken());

programming_language: Java