1 /* 2 * Copyright (C) 2022 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; 18 19 import static android.system.OsConstants.EOPNOTSUPP; 20 21 import android.net.INetd; 22 import android.os.RemoteException; 23 import android.os.ServiceSpecificException; 24 import android.system.Os; 25 import android.util.Log; 26 27 import com.android.modules.utils.build.SdkLevel; 28 29 import java.io.FileDescriptor; 30 import java.io.IOException; 31 32 /** 33 * BpfNetMaps is responsible for providing traffic controller relevant functionality. 34 * 35 * {@hide} 36 */ 37 public class BpfNetMaps { 38 private static final String TAG = "BpfNetMaps"; 39 private final INetd mNetd; 40 // Use legacy netd for releases before T. 41 private static final boolean USE_NETD = !SdkLevel.isAtLeastT(); 42 private static boolean sInitialized = false; 43 44 /** 45 * Initializes the class if it is not already initialized. This method will open maps but not 46 * cause any other effects. This method may be called multiple times on any thread. 47 */ ensureInitialized()48 private static synchronized void ensureInitialized() { 49 if (sInitialized) return; 50 if (!USE_NETD) { 51 System.loadLibrary("service-connectivity"); 52 native_init(); 53 } 54 sInitialized = true; 55 } 56 57 /** Constructor used after T that doesn't need to use netd anymore. */ BpfNetMaps()58 public BpfNetMaps() { 59 this(null); 60 61 if (USE_NETD) throw new IllegalArgumentException("BpfNetMaps need to use netd before T"); 62 } 63 BpfNetMaps(INetd netd)64 public BpfNetMaps(INetd netd) { 65 ensureInitialized(); 66 mNetd = netd; 67 } 68 maybeThrow(final int err, final String msg)69 private void maybeThrow(final int err, final String msg) { 70 if (err != 0) { 71 throw new ServiceSpecificException(err, msg + ": " + Os.strerror(err)); 72 } 73 } 74 75 /** 76 * Add naughty app bandwidth rule for specific app 77 * 78 * @param uid uid of target app 79 * @throws ServiceSpecificException in case of failure, with an error code indicating the 80 * cause of the failure. 81 */ addNaughtyApp(final int uid)82 public void addNaughtyApp(final int uid) { 83 final int err = native_addNaughtyApp(uid); 84 maybeThrow(err, "Unable to add naughty app"); 85 } 86 87 /** 88 * Remove naughty app bandwidth rule for specific app 89 * 90 * @param uid uid of target app 91 * @throws ServiceSpecificException in case of failure, with an error code indicating the 92 * cause of the failure. 93 */ removeNaughtyApp(final int uid)94 public void removeNaughtyApp(final int uid) { 95 final int err = native_removeNaughtyApp(uid); 96 maybeThrow(err, "Unable to remove naughty app"); 97 } 98 99 /** 100 * Add nice app bandwidth rule for specific app 101 * 102 * @param uid uid of target app 103 * @throws ServiceSpecificException in case of failure, with an error code indicating the 104 * cause of the failure. 105 */ addNiceApp(final int uid)106 public void addNiceApp(final int uid) { 107 final int err = native_addNiceApp(uid); 108 maybeThrow(err, "Unable to add nice app"); 109 } 110 111 /** 112 * Remove nice app bandwidth rule for specific app 113 * 114 * @param uid uid of target app 115 * @throws ServiceSpecificException in case of failure, with an error code indicating the 116 * cause of the failure. 117 */ removeNiceApp(final int uid)118 public void removeNiceApp(final int uid) { 119 final int err = native_removeNiceApp(uid); 120 maybeThrow(err, "Unable to remove nice app"); 121 } 122 123 /** 124 * Set target firewall child chain 125 * 126 * @param childChain target chain to enable 127 * @param enable whether to enable or disable child chain. 128 * @throws ServiceSpecificException in case of failure, with an error code indicating the 129 * cause of the failure. 130 */ setChildChain(final int childChain, final boolean enable)131 public void setChildChain(final int childChain, final boolean enable) { 132 final int err = native_setChildChain(childChain, enable); 133 maybeThrow(err, "Unable to set child chain"); 134 } 135 136 /** 137 * Replaces the contents of the specified UID-based firewall chain. 138 * 139 * The chain may be an allowlist chain or a denylist chain. A denylist chain contains DROP 140 * rules for the specified UIDs and a RETURN rule at the end. An allowlist chain contains RETURN 141 * rules for the system UID range (0 to {@code UID_APP} - 1), RETURN rules for the specified 142 * UIDs, and a DROP rule at the end. The chain will be created if it does not exist. 143 * 144 * @param chainName The name of the chain to replace. 145 * @param isAllowlist Whether this is an allowlist or denylist chain. 146 * @param uids The list of UIDs to allow/deny. 147 * @return 0 if the chain was successfully replaced, errno otherwise. 148 */ replaceUidChain(final String chainName, final boolean isAllowlist, final int[] uids)149 public int replaceUidChain(final String chainName, final boolean isAllowlist, 150 final int[] uids) { 151 final int err = native_replaceUidChain(chainName, isAllowlist, uids); 152 if (err != 0) { 153 Log.e(TAG, "replaceUidChain failed: " + Os.strerror(-err)); 154 } 155 return -err; 156 } 157 158 /** 159 * Set firewall rule for uid 160 * 161 * @param childChain target chain 162 * @param uid uid to allow/deny 163 * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY 164 * @throws ServiceSpecificException in case of failure, with an error code indicating the 165 * cause of the failure. 166 */ setUidRule(final int childChain, final int uid, final int firewallRule)167 public void setUidRule(final int childChain, final int uid, final int firewallRule) { 168 final int err = native_setUidRule(childChain, uid, firewallRule); 169 maybeThrow(err, "Unable to set uid rule"); 170 } 171 172 /** 173 * Add ingress interface filtering rules to a list of UIDs 174 * 175 * For a given uid, once a filtering rule is added, the kernel will only allow packets from the 176 * allowed interface and loopback to be sent to the list of UIDs. 177 * 178 * Calling this method on one or more UIDs with an existing filtering rule but a different 179 * interface name will result in the filtering rule being updated to allow the new interface 180 * instead. Otherwise calling this method will not affect existing rules set on other UIDs. 181 * 182 * @param ifName the name of the interface on which the filtering rules will allow packets to 183 * be received. 184 * @param uids an array of UIDs which the filtering rules will be set 185 * @throws RemoteException when netd has crashed. 186 * @throws ServiceSpecificException in case of failure, with an error code indicating the 187 * cause of the failure. 188 */ addUidInterfaceRules(final String ifName, final int[] uids)189 public void addUidInterfaceRules(final String ifName, final int[] uids) throws RemoteException { 190 if (USE_NETD) { 191 mNetd.firewallAddUidInterfaceRules(ifName, uids); 192 return; 193 } 194 final int err = native_addUidInterfaceRules(ifName, uids); 195 maybeThrow(err, "Unable to add uid interface rules"); 196 } 197 198 /** 199 * Remove ingress interface filtering rules from a list of UIDs 200 * 201 * Clear the ingress interface filtering rules from the list of UIDs which were previously set 202 * by addUidInterfaceRules(). Ignore any uid which does not have filtering rule. 203 * 204 * @param uids an array of UIDs from which the filtering rules will be removed 205 * @throws RemoteException when netd has crashed. 206 * @throws ServiceSpecificException in case of failure, with an error code indicating the 207 * cause of the failure. 208 */ removeUidInterfaceRules(final int[] uids)209 public void removeUidInterfaceRules(final int[] uids) throws RemoteException { 210 if (USE_NETD) { 211 mNetd.firewallRemoveUidInterfaceRules(uids); 212 return; 213 } 214 final int err = native_removeUidInterfaceRules(uids); 215 maybeThrow(err, "Unable to remove uid interface rules"); 216 } 217 218 /** 219 * Request netd to change the current active network stats map. 220 * 221 * @throws ServiceSpecificException in case of failure, with an error code indicating the 222 * cause of the failure. 223 */ swapActiveStatsMap()224 public void swapActiveStatsMap() { 225 final int err = native_swapActiveStatsMap(); 226 maybeThrow(err, "Unable to swap active stats map"); 227 } 228 229 /** 230 * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids 231 * specified. Or remove all permissions from the uids. 232 * 233 * @param permissions The permission to grant, it could be either PERMISSION_INTERNET and/or 234 * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then 235 * revoke all permissions for the uids. 236 * @param uids uid of users to grant permission 237 * @throws RemoteException when netd has crashed. 238 */ setNetPermForUids(final int permissions, final int[] uids)239 public void setNetPermForUids(final int permissions, final int[] uids) throws RemoteException { 240 if (USE_NETD) { 241 mNetd.trafficSetNetPermForUids(permissions, uids); 242 return; 243 } 244 native_setPermissionForUids(permissions, uids); 245 } 246 247 /** 248 * Dump BPF maps 249 * 250 * @param fd file descriptor to output 251 * @throws IOException when file descriptor is invalid. 252 * @throws ServiceSpecificException when the method is called on an unsupported device. 253 */ dump(final FileDescriptor fd, boolean verbose)254 public void dump(final FileDescriptor fd, boolean verbose) 255 throws IOException, ServiceSpecificException { 256 if (USE_NETD) { 257 throw new ServiceSpecificException( 258 EOPNOTSUPP, "dumpsys connectivity trafficcontroller dump not available on pre-T" 259 + " devices, use dumpsys netd trafficcontroller instead."); 260 } 261 native_dump(fd, verbose); 262 } 263 native_init()264 private static native void native_init(); native_addNaughtyApp(int uid)265 private native int native_addNaughtyApp(int uid); native_removeNaughtyApp(int uid)266 private native int native_removeNaughtyApp(int uid); native_addNiceApp(int uid)267 private native int native_addNiceApp(int uid); native_removeNiceApp(int uid)268 private native int native_removeNiceApp(int uid); native_setChildChain(int childChain, boolean enable)269 private native int native_setChildChain(int childChain, boolean enable); native_replaceUidChain(String name, boolean isAllowlist, int[] uids)270 private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids); native_setUidRule(int childChain, int uid, int firewallRule)271 private native int native_setUidRule(int childChain, int uid, int firewallRule); native_addUidInterfaceRules(String ifName, int[] uids)272 private native int native_addUidInterfaceRules(String ifName, int[] uids); native_removeUidInterfaceRules(int[] uids)273 private native int native_removeUidInterfaceRules(int[] uids); native_swapActiveStatsMap()274 private native int native_swapActiveStatsMap(); native_setPermissionForUids(int permissions, int[] uids)275 private native void native_setPermissionForUids(int permissions, int[] uids); native_dump(FileDescriptor fd, boolean verbose)276 private native void native_dump(FileDescriptor fd, boolean verbose); 277 } 278