Skip to content

Commit a18b211

Browse files
Motomu UtsumiExactExampl
authored andcommitted
Drop packets to VPN address ingressing via non-VPN interface
Cherry-pick of aosp/2795711 to backport VPN security fix to non-mainline U devices. Since isTetheringFeatureNotChickenedOut is not available on U branch, this feature is enabled on T+ devices without kill switch. Also, this CL removes test changes since CSTest utilities are not available on u branches. When there are addresses that are used by a single VPN interface, ConnectivityService sets ingress discard rules to drop packets to this address from the non-Vpn interfaces Bug: 193031925 Test: TH (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d493a3aa7dcca3219b139616c9de3c6ee8181f86) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1027bc813ea6a5b97bc0f55401e01f5eec91e94a) Merged-In: I5933d42f3fd257139fb803ede1391e10d9d1211b Change-Id: I5933d42f3fd257139fb803ede1391e10d9d1211b
1 parent 5a6dd4d commit a18b211

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

service/src/com/android/server/ConnectivityService.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,9 @@ private static IDnsResolver getDnsResolver(Context context) {
936936
private final Map<String, ApplicationSelfCertifiedNetworkCapabilities>
937937
mSelfCertifiedCapabilityCache = new HashMap<>();
938938

939+
// Flag to drop packets to VPN addresses ingressing via non-VPN interfaces.
940+
private final boolean mIngressToVpnAddressFiltering;
941+
939942
/**
940943
* Implements support for the legacy "one network per network type" model.
941944
*
@@ -1798,6 +1801,7 @@ public void onUidFrozenStateChanged(int[] uids, int[] frozenStates) {
17981801
activityManager.registerUidFrozenStateChangedCallback(
17991802
(Runnable r) -> r.run(), frozenStateChangedCallback);
18001803
}
1804+
mIngressToVpnAddressFiltering = mDeps.isAtLeastT();
18011805
}
18021806

18031807
/**
@@ -4776,6 +4780,7 @@ private void destroyNativeNetwork(@NonNull NetworkAgentInfo nai) {
47764780
if (mDscpPolicyTracker != null) {
47774781
mDscpPolicyTracker.removeAllDscpPolicies(nai, false);
47784782
}
4783+
updateIngressToVpnAddressFiltering(null, nai.linkProperties, nai);
47794784
try {
47804785
mNetd.networkDestroy(nai.network.getNetId());
47814786
} catch (RemoteException | ServiceSpecificException e) {
@@ -8014,6 +8019,8 @@ private void updateLinkProperties(NetworkAgentInfo networkAgent, @NonNull LinkPr
80148019
// new interface (the interface name -> index map becomes initialized)
80158020
updateVpnFiltering(newLp, oldLp, networkAgent);
80168021

8022+
updateIngressToVpnAddressFiltering(newLp, oldLp, networkAgent);
8023+
80178024
updateMtu(newLp, oldLp);
80188025
// TODO - figure out what to do for clat
80198026
// for (LinkProperties lp : newLp.getStackedLinks()) {
@@ -8337,6 +8344,87 @@ private void updateVpnFiltering(@NonNull LinkProperties newLp, @Nullable LinkPro
83378344
}
83388345
}
83398346

8347+
/**
8348+
* Returns ingress discard rules to drop packets to VPN addresses ingressing via non-VPN
8349+
* interfaces.
8350+
* Ingress discard rule is added to the address iff
8351+
* 1. The address is not a link local address
8352+
* 2. The address is used by a single VPN interface and not used by any other
8353+
* interfaces even non-VPN ones
8354+
* This method can be called during network disconnects, when nai has already been removed from
8355+
* mNetworkAgentInfos.
8356+
*
8357+
* @param nai This method generates rules assuming lp of this nai is the lp at the second
8358+
* argument.
8359+
* @param lp This method generates rules assuming lp of nai at the first argument is this lp.
8360+
* Caller passes old lp to generate old rules and new lp to generate new rules.
8361+
* @return ingress discard rules. Set of pairs of addresses and interface names
8362+
*/
8363+
private Set<Pair<InetAddress, String>> generateIngressDiscardRules(
8364+
@NonNull final NetworkAgentInfo nai, @Nullable final LinkProperties lp) {
8365+
Set<NetworkAgentInfo> nais = new ArraySet<>(mNetworkAgentInfos);
8366+
nais.add(nai);
8367+
// Determine how many networks each IP address is currently configured on.
8368+
// Ingress rules are added only for IP addresses that are configured on single interface.
8369+
final Map<InetAddress, Integer> addressOwnerCounts = new ArrayMap<>();
8370+
for (final NetworkAgentInfo agent : nais) {
8371+
if (agent.isDestroyed()) {
8372+
continue;
8373+
}
8374+
final LinkProperties agentLp = (nai == agent) ? lp : agent.linkProperties;
8375+
if (agentLp == null) {
8376+
continue;
8377+
}
8378+
for (final InetAddress addr: agentLp.getAllAddresses()) {
8379+
addressOwnerCounts.put(addr, addressOwnerCounts.getOrDefault(addr, 0) + 1);
8380+
}
8381+
}
8382+
8383+
// Iterates all networks instead of only generating rule for nai that was passed in since
8384+
// lp of the nai change could cause/resolve address collision and result in affecting rule
8385+
// for different network.
8386+
final Set<Pair<InetAddress, String>> ingressDiscardRules = new ArraySet<>();
8387+
for (final NetworkAgentInfo agent : nais) {
8388+
if (!agent.isVPN() || agent.isDestroyed()) {
8389+
continue;
8390+
}
8391+
final LinkProperties agentLp = (nai == agent) ? lp : agent.linkProperties;
8392+
if (agentLp == null || agentLp.getInterfaceName() == null) {
8393+
continue;
8394+
}
8395+
8396+
for (final InetAddress addr: agentLp.getAllAddresses()) {
8397+
if (addressOwnerCounts.get(addr) == 1 && !addr.isLinkLocalAddress()) {
8398+
ingressDiscardRules.add(new Pair<>(addr, agentLp.getInterfaceName()));
8399+
}
8400+
}
8401+
}
8402+
return ingressDiscardRules;
8403+
}
8404+
8405+
private void updateIngressToVpnAddressFiltering(@Nullable LinkProperties newLp,
8406+
@Nullable LinkProperties oldLp, @NonNull NetworkAgentInfo nai) {
8407+
// Having isAtleastT to avoid NewApi linter error (b/303382209)
8408+
if (!mIngressToVpnAddressFiltering || !mDeps.isAtLeastT()) {
8409+
return;
8410+
}
8411+
final CompareOrUpdateResult<InetAddress, Pair<InetAddress, String>> ruleDiff =
8412+
new CompareOrUpdateResult<>(
8413+
generateIngressDiscardRules(nai, oldLp),
8414+
generateIngressDiscardRules(nai, newLp),
8415+
(rule) -> rule.first);
8416+
for (Pair<InetAddress, String> rule: ruleDiff.removed) {
8417+
mBpfNetMaps.removeIngressDiscardRule(rule.first);
8418+
}
8419+
for (Pair<InetAddress, String> rule: ruleDiff.added) {
8420+
mBpfNetMaps.setIngressDiscardRule(rule.first, rule.second);
8421+
}
8422+
// setIngressDiscardRule overrides the existing rule
8423+
for (Pair<InetAddress, String> rule: ruleDiff.updated) {
8424+
mBpfNetMaps.setIngressDiscardRule(rule.first, rule.second);
8425+
}
8426+
}
8427+
83408428
private void updateWakeOnLan(@NonNull LinkProperties lp) {
83418429
if (mWolSupportedInterfaces == null) {
83428430
mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray(

0 commit comments

Comments
 (0)