• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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