From b9dca4855ed9bf9fce0b6bedc955ece4914350a6 Mon Sep 17 00:00:00 2001 From: Oliver Scott <olivercscott@gmail.com> Date: Thu, 8 Jul 2021 10:41:43 -0400 Subject: [PATCH] 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 <olivercscott@gmail.com> 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 <ikeramat@protonmail.com> --- .../policy/SecurityControllerImpl.java | 10 ++++- .../com/android/server/connectivity/Vpn.java | 39 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) 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 03656f000c07..77a57097becd 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; @@ -58,6 +59,8 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.settings.UserTracker; +import com.libremobileos.providers.LMOSettings; + import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; @@ -338,8 +341,13 @@ public class SecurityControllerImpl implements SecurityController { @Override public void onUserSwitched(int newUserId) { mCurrentUserId = newUserId; + final String globalVpnApp = Settings.Global.getString(mContext.getContentResolver(), + LMOSettings.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 e3262cfbd30b..7e83b087dd3a 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -163,6 +163,8 @@ import com.android.server.net.BaseNetworkObserver; import com.android.server.vcn.util.MtuUtils; import com.android.server.vcn.util.PersistableBundleUtils; +import com.libremobileos.providers.LMOSettings; + import libcore.io.IoUtils; import java.io.File; @@ -915,6 +917,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(), + LMOSettings.Global.GLOBAL_VPN_APP); + return mUserId == UserHandle.USER_SYSTEM && mPackage.equals(globalVpnPkg); + } + /** * Checks if a VPN app supports always-on mode. * @@ -1864,6 +1875,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) { @@ -2016,7 +2028,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<UserInfo> users; try { @@ -2025,7 +2037,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); } } @@ -2106,7 +2119,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<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { @@ -2135,7 +2149,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<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { @@ -2580,6 +2595,17 @@ public class Vpn { } } + private void enforceNotGlobalVpn() { + Binder.withCleanCallingIdentity(() -> { + if (mUserId != UserHandle.USER_SYSTEM && !TextUtils.isEmpty( + Settings.Global.getString(mContext.getContentResolver(), + LMOSettings.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. @@ -2664,6 +2690,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(); @@ -4621,6 +4648,7 @@ public class Vpn { verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); + enforceNotGlobalVpn(); validateRequiredFeatures(profile); if (profile.isRestrictedToTestNetworks) { @@ -4663,6 +4691,7 @@ public class Vpn { verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); + enforceNotGlobalVpn(); final long token = Binder.clearCallingIdentity(); try { @@ -4732,6 +4761,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)) { @@ -4856,6 +4886,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. -- GitLab