Prevent an app to check if the specified VPN app is set VPN always-on

An app can check if the specified VPN app is set VPN always-on
or not by calling VpnManagerService#prepareVpn(). If it sets
oldPackage to null and newPackage to a specified VPN app which
is set always-on, then prepareVpn() will return true. So the app
could know the specified VPN app is installed and it's set
always-on.

Bug: 191276656
Test: atest FrameworksNetTests CtsNetTestCases \
      CtsHostsideNetworkTests:HostsideVpnTests
Change-Id: I0013039f58a6f7c5c73b9acc877d70a0126d0ca7
Merged-In: I0013039f58a6f7c5c73b9acc877d70a0126d0ca7
This commit is contained in:
lucaslin
2021-09-09 14:46:06 +08:00
committed by Lucas Lin
parent 5dddce9aa2
commit d8ec51ac8b

View File

@@ -17,6 +17,8 @@
package com.android.server.connectivity; package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE; import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.Manifest.permission.CONTROL_VPN;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -932,6 +934,7 @@ public class Vpn {
* - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn(). * - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn().
* - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect * - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect
* and revoke any current app VPN and re-prepare legacy vpn. * and revoke any current app VPN and re-prepare legacy vpn.
* - oldPackage null, newPackage null: always returns true for backward compatibility.
* *
* TODO: Rename the variables - or split this method into two - and end this confusion. * TODO: Rename the variables - or split this method into two - and end this confusion.
* TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN) * TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN)
@@ -945,6 +948,18 @@ public class Vpn {
*/ */
public synchronized boolean prepare( public synchronized boolean prepare(
String oldPackage, String newPackage, @VpnManager.VpnType int vpnType) { String oldPackage, String newPackage, @VpnManager.VpnType int vpnType) {
// Except for Settings and VpnDialogs, the caller should be matched one of oldPackage or
// newPackage. Otherwise, non VPN owner might get the VPN always-on status of the VPN owner.
// See b/191382886.
if (mContext.checkCallingOrSelfPermission(CONTROL_VPN) != PERMISSION_GRANTED) {
if (oldPackage != null) {
verifyCallingUidAndPackage(oldPackage);
}
if (newPackage != null) {
verifyCallingUidAndPackage(newPackage);
}
}
if (oldPackage != null) { if (oldPackage != null) {
// Stop an existing always-on VPN from being dethroned by other apps. // Stop an existing always-on VPN from being dethroned by other apps.
if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) { if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) {
@@ -1859,14 +1874,13 @@ public class Vpn {
} }
private void enforceControlPermission() { private void enforceControlPermission() {
mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller"); mContext.enforceCallingPermission(CONTROL_VPN, "Unauthorized Caller");
} }
private void enforceControlPermissionOrInternalCaller() { private void enforceControlPermissionOrInternalCaller() {
// Require the caller to be either an application with CONTROL_VPN permission or a process // Require the caller to be either an application with CONTROL_VPN permission or a process
// in the system server. // in the system server.
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN, mContext.enforceCallingOrSelfPermission(CONTROL_VPN, "Unauthorized Caller");
"Unauthorized Caller");
} }
private void enforceSettingsPermission() { private void enforceSettingsPermission() {
@@ -3176,8 +3190,9 @@ public class Vpn {
} }
private void verifyCallingUidAndPackage(String packageName) { private void verifyCallingUidAndPackage(String packageName) {
if (getAppUid(packageName, mUserId) != Binder.getCallingUid()) { final int callingUid = Binder.getCallingUid();
throw new SecurityException("Mismatched package and UID"); if (getAppUid(packageName, mUserId) != callingUid) {
throw new SecurityException(packageName + " does not belong to uid " + callingUid);
} }
} }