From af0cbe50e889694dc72ab84c4e1af816bdd199b9 Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Thu, 8 Jul 2021 10:41:43 -0400 Subject: [PATCH 4/6] Global VPN feature [1/2] * Modify existing VPN user range functions to conditionally have traffic from all users pass through the global VPN. These functions are called when: 1. Starting a VPN 2. Adding a user 3. Removing a user * Disallow starting VPNs in secondary users when a global VPN is set Also includes: Author: Oliver Scott Date: 2021-08-27 16:30:22 -0400 Show Global VPN icon on all users Change-Id: I496c0abbdf92b8f823bc57b297473aa14bd968c8 Change-Id: I42616cc1f4e39e1dad739d81f6d5c55e218be995 Signed-off-by: Mohammad Hasan Keramat J --- core/java/android/provider/Settings.java | 6 +++ .../policy/SecurityControllerImpl.java | 8 +++- .../com/android/server/connectivity/Vpn.java | 37 +++++++++++++++++-- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 8d8379831e87..bd6cc1d4d7bf 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -16060,6 +16060,12 @@ public final class Settings { CLOCKWORK_HOME_READY, }; + /** + * Package designated as global VPN provider. + * @hide + */ + public static final String GLOBAL_VPN_APP = "global_vpn_app"; + /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index ba947149d287..e5eb04c7818d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -39,6 +39,7 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.security.KeyChain; import android.util.ArrayMap; import android.util.Log; @@ -332,8 +333,13 @@ public class SecurityControllerImpl implements SecurityController { @Override public void onUserSwitched(int newUserId) { mCurrentUserId = newUserId; + final String globalVpnApp = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.GLOBAL_VPN_APP); final UserInfo newUserInfo = mUserManager.getUserInfo(newUserId); - if (newUserInfo.isRestricted()) { + if (mCurrentVpns.get(UserHandle.USER_SYSTEM) != null && + mCurrentVpns.get(UserHandle.USER_SYSTEM).user.equals(globalVpnApp)) { + mVpnUserId = UserHandle.USER_SYSTEM; + } else if (newUserInfo.isRestricted()) { // VPN for a restricted profile is routed through its owner user mVpnUserId = newUserInfo.restrictedProfileParentId; } else { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 8510de4ef201..7c02924a711d 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -691,6 +691,15 @@ public class Vpn { return mAlwaysOn; } + /** + * Returns whether currently prepared VPN package is set as the global VPN. + */ + private synchronized boolean isGlobalVpn() { + final String globalVpnPkg = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.GLOBAL_VPN_APP); + return mUserId == UserHandle.USER_SYSTEM && mPackage.equals(globalVpnPkg); + } + /** * Checks if a VPN app supports always-on mode. * @@ -1559,6 +1568,7 @@ public class Vpn { try { // Restricted users are not allowed to create VPNs, they are tied to Owner enforceNotRestrictedUser(); + enforceNotGlobalVpn(); final PackageManager packageManager = mUserIdContext.getPackageManager(); if (packageManager == null) { @@ -1720,7 +1730,7 @@ public class Vpn { addUserToRanges(ranges, userId, allowedApplications, disallowedApplications); // If the user can have restricted profiles, assign all its restricted profiles too - if (canHaveRestrictedProfile(userId)) { + if (canHaveRestrictedProfile(userId) || isGlobalVpn()) { final long token = Binder.clearCallingIdentity(); List users; try { @@ -1729,7 +1739,8 @@ public class Vpn { Binder.restoreCallingIdentity(token); } for (UserInfo user : users) { - if (user.isRestricted() && (user.restrictedProfileParentId == userId)) { + if ((user.isRestricted() && (user.restrictedProfileParentId == userId)) + || isGlobalVpn()) { addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications); } } @@ -1810,7 +1821,8 @@ public class Vpn { public void onUserAdded(int userId) { // If the user is restricted tie them to the parent user's VPN UserInfo user = mUserManager.getUserInfo(userId); - if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { + if ((user.isRestricted() && user.restrictedProfileParentId == mUserId) || + isGlobalVpn()) { synchronized(Vpn.this) { final Set> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { @@ -1839,7 +1851,8 @@ public class Vpn { public void onUserRemoved(int userId) { // clean up if restricted UserInfo user = mUserManager.getUserInfo(userId); - if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { + if ((user.isRestricted() && user.restrictedProfileParentId == mUserId) || + isGlobalVpn()) { synchronized(Vpn.this) { final Set> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { @@ -2278,6 +2291,17 @@ public class Vpn { } } + private void enforceNotGlobalVpn() { + Binder.withCleanCallingIdentity(() -> { + if (mUserId != UserHandle.USER_SYSTEM && !TextUtils.isEmpty( + Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.GLOBAL_VPN_APP))) { + throw new SecurityException("Secondary users cannot configure VPNs when" + + " global vpn is set"); + } + }); + } + /** * Start legacy VPN, controlling native daemons as needed. Creates a * secondary thread to perform connection work, returning quickly. @@ -2362,6 +2386,7 @@ public class Vpn { new UserHandle(mUserId))) { throw new SecurityException("Restricted users cannot establish VPNs"); } + enforceNotGlobalVpn(); final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress); final String gateway = ipv4DefaultRoute.getGateway().getHostAddress(); @@ -3859,6 +3884,7 @@ public class Vpn { verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); + enforceNotGlobalVpn(); validateRequiredFeatures(profile); if (profile.isRestrictedToTestNetworks) { @@ -3901,6 +3927,7 @@ public class Vpn { verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); + enforceNotGlobalVpn(); final long token = Binder.clearCallingIdentity(); try { @@ -3964,6 +3991,7 @@ public class Vpn { requireNonNull(packageName, "No package name provided"); enforceNotRestrictedUser(); + enforceNotGlobalVpn(); // Prepare VPN for startup if (!prepare(packageName, null /* newPackage */, VpnManager.TYPE_VPN_PLATFORM)) { @@ -4085,6 +4113,7 @@ public class Vpn { requireNonNull(packageName, "No package name provided"); enforceNotRestrictedUser(); + enforceNotGlobalVpn(); // To stop the VPN profile, the caller must be the current prepared package and must be // running an Ikev2VpnProfile. -- 2.41.0