1616
1717package org .microg .gms .gservices ;
1818
19+ import static android .os .Build .VERSION .SDK_INT ;
20+
21+ import android .app .admin .DevicePolicyManager ;
1922import android .content .ContentProvider ;
2023import android .content .ContentValues ;
24+ import android .content .pm .PackageManager ;
2125import android .database .Cursor ;
2226import android .database .MatrixCursor ;
2327import android .net .Uri ;
28+ import android .os .Binder ;
29+ import android .os .Process ;
2430import android .util .Log ;
2531
32+ import androidx .core .content .ContextCompat ;
33+
34+ import java .util .Arrays ;
2635import java .util .HashMap ;
2736import java .util .HashSet ;
2837import java .util .Iterator ;
2938import java .util .Map ;
3039import java .util .Set ;
3140
32- import static android . os . Build . VERSION . SDK_INT ;
41+ import org . microg . gms . utils . ExtendedPackageInfo ;
3342
3443/**
3544 * Originally found in Google Services Framework (com.google.android.gsf), this provides a generic
@@ -56,16 +65,61 @@ public boolean onCreate() {
5665 return true ;
5766 }
5867
59- private String getCallingPackageName () {
60- if (SDK_INT >= 19 ) {
61- return getCallingPackage ();
62- } else {
63- return "unknown" ;
68+ private boolean callerIsGoogle () {
69+ try {
70+ String packageName = getCallingPackage ();
71+ if (packageName == null ) return false ;
72+ PackageManager packageManager = getContext ().getPackageManager ();
73+ return new ExtendedPackageInfo (packageManager , packageName ).isGooglePackage ();
74+ } catch (Exception e ) {
75+ return false ;
76+ }
77+ }
78+
79+ private boolean callerIsOwner () {
80+ try {
81+ String packageName = getCallingPackage ();
82+ if (packageName == null ) return false ;
83+ DevicePolicyManager devicePolicyManager = ContextCompat .getSystemService (getContext (), DevicePolicyManager .class );
84+ return devicePolicyManager .isDeviceOwnerApp (packageName ) || (SDK_INT >= 21 && devicePolicyManager .isProfileOwnerApp (packageName ));
85+ } catch (Exception e ) {
86+ return false ;
87+ }
88+ }
89+
90+ /**
91+ * Instead of checking if the permissions is granted, we only check if it was requested.
92+ * <p>
93+ * This is because:
94+ * <ul>
95+ * <li>
96+ * this is a permission with protectionLevel normal and requesting should usually
97+ * silently grant it, as Android no longer asks users to confirm install-time
98+ * permissions on installation
99+ * </li>
100+ * <li>
101+ * on some Android versions, requesting a permission that is not declared yet will not
102+ * grant that permission if the declaring app is installed later
103+ * </li>
104+ * </ul>
105+ */
106+ private boolean callerHasReadPermissionRequested () {
107+ String packageName = getCallingPackage ();
108+ if (packageName == null ) return false ;
109+ try {
110+ String [] requestedPermissions = getContext ().getPackageManager ().getPackageInfo (packageName , PackageManager .GET_PERMISSIONS ).requestedPermissions ;
111+ return requestedPermissions != null && Arrays .asList (requestedPermissions ).contains ("com.google.android.providers.gsf.permission.READ_GSERVICES" );
112+ } catch (PackageManager .NameNotFoundException e ) {
113+ return false ;
64114 }
65115 }
66116
67117 @ Override
68118 public Cursor query (Uri uri , String [] projection , String selection , String [] selectionArgs , String sortOrder ) {
119+ if (Binder .getCallingUid () != Process .myUid () && !callerIsGoogle () && !callerHasReadPermissionRequested ()) {
120+ Log .w (TAG , "Rejected read access for package " + getCallingPackage ());
121+ return null ;
122+ }
69123 MatrixCursor cursor = new MatrixCursor (new String []{"name" , "value" });
70124 if (PREFIX_URI .equals (uri )) {
71125 for (String prefix : selectionArgs ) {
@@ -92,6 +146,15 @@ public Cursor query(Uri uri, String[] projection, String selection, String[] sel
92146 value = databaseHelper .get (name );
93147 cache .put (name , value );
94148 }
149+ if ("android_id" .equals (name )) {
150+ // Only Google and device/profile owner can access android_id
151+ if (Binder .getCallingUid () != Process .myUid () && !callerIsGoogle () && !callerIsOwner ()) {
152+ Log .w (TAG , "Rejected access to android_id for package " + getCallingPackage ());
153+ value = null ;
154+ } else {
155+ Log .d (TAG , "Granted access to android_id for package " + getCallingPackage ());
156+ }
157+ }
95158 if (value != null ) {
96159 cursor .addRow (new String []{name , value });
97160 }
@@ -118,7 +181,11 @@ public int delete(Uri uri, String selection, String[] selectionArgs) {
118181
119182 @ Override
120183 public int update (Uri uri , ContentValues values , String selection , String [] selectionArgs ) {
121- Log .d (TAG , "update caller=" + getCallingPackageName () + " table=" + uri .getLastPathSegment ()
184+ if (Binder .getCallingUid () != Process .myUid () && !callerIsGoogle ()) {
185+ Log .w (TAG , "Rejected write access for package " + getCallingPackage ());
186+ return 0 ;
187+ }
188+ Log .d (TAG , "update caller=" + getCallingPackage () + " table=" + uri .getLastPathSegment ()
122189 + " name=" + values .getAsString ("name" ) + " value=" + values .getAsString ("value" ));
123190 if (uri .equals (MAIN_URI )) {
124191 databaseHelper .put ("main" , values );
0 commit comments