1 /*
2  * Copyright (C) 2018 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 com.android.server.util;
18 
19 import static android.Manifest.permission.NETWORK_SETTINGS;
20 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
21 import static android.os.Binder.getCallingPid;
22 import static android.os.Binder.getCallingUid;
23 
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.os.Process;
27 import android.os.SystemProperties;
28 import android.os.UserHandle;
29 
30 import java.util.Arrays;
31 import java.util.concurrent.atomic.AtomicInteger;
32 
33 /**
34  * Utility class to check calling permissions on the network stack.
35  */
36 public final class PermissionUtil {
37     private static final AtomicInteger sSystemPid = new AtomicInteger(-1);
38 
39     private static volatile int sTestUid = Process.INVALID_UID;
40 
41     /**
42      * Check that the caller is allowed to communicate with the network stack.
43      * @throws SecurityException The caller is not allowed to communicate with the network stack.
44      */
enforceNetworkStackCallingPermission()45     public static void enforceNetworkStackCallingPermission() {
46         final int caller = getCallingUid();
47         if (caller == Process.SYSTEM_UID) {
48             checkConsistentSystemPid();
49             return;
50         }
51 
52         if (caller != Process.myUid() // apps with NETWORK_STACK_UID
53                 && UserHandle.getAppId(caller) != Process.BLUETOOTH_UID
54                 && !isTestUid(caller)) {
55             throw new SecurityException("Invalid caller: " + caller);
56         }
57     }
58 
checkConsistentSystemPid()59     private static void checkConsistentSystemPid() {
60         // Apart from the system server process, no process with a system UID should try to
61         // communicate with the network stack. This is to ensure that the network stack does not
62         // need to maintain behavior for clients it was not designed to work with.
63         // Checking that all calls from a system UID originate from the same PID loosely enforces
64         // this restriction as if another system process calls the network stack first, the system
65         // server would lose access to the network stack and cause obvious failures. If the system
66         // server calls the network stack first, other clients would lose access as expected.
67         final int systemPid = getCallingPid();
68         if (sSystemPid.compareAndSet(-1, systemPid)) {
69             // sSystemPid was unset (-1): this was the first call
70             return;
71         }
72 
73         if (sSystemPid.get() != systemPid) {
74             throw new SecurityException("Invalid PID for the system server, expected "
75                     + sSystemPid.get() + " but was called from " + systemPid);
76         }
77     }
78 
isTestUid(int uid)79     private static boolean isTestUid(int uid) {
80         return uid == sTestUid;
81     }
82 
83     /**
84      * Set a test uid that is allowed to call the NetworkStack. Pass in -1 to reset.
85      *
86      * <p>The UID must have a package with NETWORK_SETTINGS permissions when it is allowed.
87      */
setTestUid(Context context, int uid)88     public static void setTestUid(Context context, int uid) {
89         if (!isDebuggableBuild()) {
90             throw new SecurityException("Cannot set test UID on non-debuggable builds");
91         }
92         if (getCallingUid() != Process.ROOT_UID) {
93             throw new SecurityException("Only root can set the test UID");
94         }
95 
96         if (uid == Process.INVALID_UID) {
97             sTestUid = uid;
98             return;
99         }
100 
101         final PackageManager pm = context.getPackageManager();
102         final String[] packages = pm.getPackagesForUid(uid);
103         if (packages == null) {
104             throw new SecurityException("No package in uid " + uid);
105         }
106         final boolean hasPermission = Arrays.stream(packages).anyMatch(
107                 p -> pm.checkPermission(NETWORK_SETTINGS, p) == PERMISSION_GRANTED);
108         if (!hasPermission) {
109             throw new SecurityException(
110                     "The uid must have a package with NETWORK_SETTINGS permissions");
111         }
112         sTestUid = uid;
113     }
114 
115     /**
116      * Check that the caller is allowed to dump the network stack, e.g. dumpsys.
117      * @throws SecurityException The caller is not allowed to dump the network stack.
118      */
checkDumpPermission()119     public static void checkDumpPermission() {
120         final int caller = getCallingUid();
121         if (caller != Process.myUid() && caller != Process.SYSTEM_UID && caller != Process.ROOT_UID
122                 && caller != Process.SHELL_UID) {
123             throw new SecurityException("No dump permissions for caller: " + caller);
124         }
125     }
126 
127     /**
128      * @see android.os.Build.IS_DEBUGGABLE
129      */
isDebuggableBuild()130     public static boolean isDebuggableBuild() {
131         // TODO: consider adding Build.IS_DEBUGGABLE to @SystemApi
132         return SystemProperties.getInt("ro.debuggable", 0) == 1;
133     }
134 
PermissionUtil()135     private PermissionUtil() {
136         throw new UnsupportedOperationException("This class is not to be instantiated");
137     }
138 }
139