1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net;
18 
19 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
20 import static android.net.NetworkStats.UID_ALL;
21 import static android.net.TrafficStats.UID_REMOVED;
22 import static android.net.TrafficStats.UID_TETHERING;
23 
24 import android.Manifest;
25 import android.annotation.IntDef;
26 import android.annotation.Nullable;
27 import android.app.AppOpsManager;
28 import android.app.admin.DevicePolicyManager;
29 import android.content.Context;
30 import android.content.pm.PackageManager;
31 import android.os.Binder;
32 import android.os.Process;
33 import android.os.UserHandle;
34 import android.telephony.TelephonyManager;
35 
36 import com.android.net.module.util.PermissionUtils;
37 
38 import java.lang.annotation.Retention;
39 import java.lang.annotation.RetentionPolicy;
40 
41 /**
42  * Utility methods for controlling access to network stats APIs.
43  *
44  * @hide
45  */
46 public final class NetworkStatsAccess {
NetworkStatsAccess()47     private NetworkStatsAccess() {}
48 
49     /**
50      * Represents an access level for the network usage history and statistics APIs.
51      *
52      * <p>Access levels are in increasing order; that is, it is reasonable to check access by
53      * verifying that the caller's access level is at least the minimum required level.
54      */
55     @IntDef({
56             Level.DEFAULT,
57             Level.USER,
58             Level.DEVICESUMMARY,
59             Level.DEVICE,
60     })
61     @Retention(RetentionPolicy.SOURCE)
62     public @interface Level {
63         /**
64          * Default, unprivileged access level.
65          *
66          * <p>Can only access usage for one's own UID.
67          *
68          * <p>Every app will have at least this access level.
69          */
70         int DEFAULT = 0;
71 
72         /**
73          * Access level for apps which can access usage for any app running in the same user.
74          *
75          * <p>Granted to:
76          * <ul>
77          * <li>Profile owners.
78          * </ul>
79          */
80         int USER = 1;
81 
82         /**
83          * Access level for apps which can access usage summary of device. Device summary includes
84          * usage by apps running in any profiles/users, however this access level does not
85          * allow querying usage of individual apps running in other profiles/users.
86          *
87          * <p>Granted to:
88          * <ul>
89          * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
90          * so it is not necessarily sufficient to declare this in the manifest.
91          * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
92          * </ul>
93          */
94         int DEVICESUMMARY = 2;
95 
96         /**
97          * Access level for apps which can access usage for any app on the device, including apps
98          * running on other users/profiles.
99          *
100          * <p>Granted to:
101          * <ul>
102          * <li>Device owners.
103          * <li>Carrier-privileged applications.
104          * <li>The system UID.
105          * <li>NetworkStack application.
106          * </ul>
107          */
108         int DEVICE = 3;
109     }
110 
111     /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
checkAccessLevel( Context context, int callingPid, int callingUid, @Nullable String callingPackage)112     public static @NetworkStatsAccess.Level int checkAccessLevel(
113             Context context, int callingPid, int callingUid, @Nullable String callingPackage) {
114         final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class);
115         final TelephonyManager tm = (TelephonyManager)
116                 context.getSystemService(Context.TELEPHONY_SERVICE);
117         final boolean hasCarrierPrivileges;
118         final boolean isDeviceOwner;
119         long token = Binder.clearCallingIdentity();
120         try {
121             hasCarrierPrivileges = tm != null
122                     && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
123                             == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
124             isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage);
125         } finally {
126             Binder.restoreCallingIdentity(token);
127         }
128 
129         final int appId = UserHandle.getAppId(callingUid);
130 
131         final boolean isNetworkStack = PermissionUtils.hasAnyPermissionOf(
132                 context, callingPid, callingUid, android.Manifest.permission.NETWORK_STACK,
133                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
134 
135         if (hasCarrierPrivileges || isDeviceOwner
136                 || appId == Process.SYSTEM_UID || isNetworkStack) {
137             // Carrier-privileged apps and device owners, and the system (including the
138             // network stack) can access data usage for all apps on the device.
139             return NetworkStatsAccess.Level.DEVICE;
140         }
141 
142         final boolean hasAppOpsPermission =
143                 hasAppOpsPermission(context, callingUid, callingPackage);
144         if (hasAppOpsPermission || context.checkCallingOrSelfPermission(
145                 READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) {
146             return NetworkStatsAccess.Level.DEVICESUMMARY;
147         }
148 
149         final boolean isProfileOwner;
150         token = Binder.clearCallingIdentity();
151         try {
152             isProfileOwner = mDpm != null && mDpm.isProfileOwnerApp(callingPackage);
153         } finally {
154             Binder.restoreCallingIdentity(token);
155         }
156         if (isProfileOwner) {
157             // Apps with the AppOps permission, profile owners, and apps with the privileged
158             // permission can access data usage for all apps in this user/profile.
159             return NetworkStatsAccess.Level.USER;
160         }
161 
162         // Everyone else gets default access (only to their own UID).
163         return NetworkStatsAccess.Level.DEFAULT;
164     }
165 
166     /**
167      * Returns whether the given caller should be able to access the given UID when the caller has
168      * the given {@link NetworkStatsAccess.Level}.
169      */
isAccessibleToUser(int uid, int callerUid, @NetworkStatsAccess.Level int accessLevel)170     public static boolean isAccessibleToUser(int uid, int callerUid,
171             @NetworkStatsAccess.Level int accessLevel) {
172         final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
173         final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier();
174         switch (accessLevel) {
175             case NetworkStatsAccess.Level.DEVICE:
176                 // Device-level access - can access usage for any uid.
177                 return true;
178             case NetworkStatsAccess.Level.DEVICESUMMARY:
179                 // Can access usage for any app running in the same user, along
180                 // with some special uids (system, removed, or tethering) and
181                 // anonymized uids
182                 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
183                         || uid == UID_TETHERING || uid == UID_ALL
184                         || userId == callerUserId;
185             case NetworkStatsAccess.Level.USER:
186                 // User-level access - can access usage for any app running in the same user, along
187                 // with some special uids (system, removed, or tethering).
188                 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
189                         || uid == UID_TETHERING
190                         || userId == callerUserId;
191             case NetworkStatsAccess.Level.DEFAULT:
192             default:
193                 // Default access level - can only access one's own usage.
194                 return uid == callerUid;
195         }
196     }
197 
hasAppOpsPermission( Context context, int callingUid, String callingPackage)198     private static boolean hasAppOpsPermission(
199             Context context, int callingUid, String callingPackage) {
200         if (callingPackage != null) {
201             AppOpsManager appOps = (AppOpsManager) context.getSystemService(
202                     Context.APP_OPS_SERVICE);
203 
204             final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS,
205                     callingUid, callingPackage, null /* attributionTag */, null /* message */);
206             if (mode == AppOpsManager.MODE_DEFAULT) {
207                 // The default behavior here is to check if PackageManager has given the app
208                 // permission.
209                 final int permissionCheck = context.checkCallingPermission(
210                         Manifest.permission.PACKAGE_USAGE_STATS);
211                 return permissionCheck == PackageManager.PERMISSION_GRANTED;
212             }
213             return (mode == AppOpsManager.MODE_ALLOWED);
214         }
215         return false;
216     }
217 }
218