diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 3a3ddcc483..d6774d47b4 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -45,25 +45,31 @@ interface IIpSecService in String localAddr, in String remoteAddr, in Network underlyingNetwork, - in IBinder binder); + in IBinder binder, + in String callingPackage); void addAddressToTunnelInterface( int tunnelResourceId, - in LinkAddress localAddr); + in LinkAddress localAddr, + in String callingPackage); void removeAddressFromTunnelInterface( int tunnelResourceId, - in LinkAddress localAddr); + in LinkAddress localAddr, + in String callingPackage); - void deleteTunnelInterface(int resourceId); + void deleteTunnelInterface(int resourceId, in String callingPackage); - IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder); + IpSecTransformResponse createTransform( + in IpSecConfig c, in IBinder binder, in String callingPackage); void deleteTransform(int transformId); - void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); + void applyTransportModeTransform( + in ParcelFileDescriptor socket, int direction, int transformId); - void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId); + void applyTunnelModeTransform( + int tunnelResourceId, int direction, int transformResourceId, in String callingPackage); void removeTransportModeTransforms(in ParcelFileDescriptor socket); } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index cc227713cb..1145d5bd4d 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -27,6 +27,9 @@ import android.content.Context; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.system.ErrnoException; +import android.system.OsConstants; import android.util.AndroidException; import android.util.Log; @@ -140,6 +143,7 @@ public final class IpSecManager { } } + private final Context mContext; private final IIpSecService mService; /** @@ -172,11 +176,16 @@ public final class IpSecManager { public void close() { try { mService.releaseSecurityParameterIndex(mResourceId); - mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } - mCloseGuard.close(); } /** Check that the SPI was closed properly. */ @@ -227,7 +236,6 @@ public final class IpSecManager { throw new RuntimeException( "Invalid Resource ID returned by IpSecService: " + status); } - } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -239,6 +247,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("SecurityParameterIndex{spi=") + .append(mSpi) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } /** @@ -261,7 +280,11 @@ public final class IpSecManager { mService, destinationAddress, IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + } catch (ServiceSpecificException e) { + throw rethrowUncheckedExceptionFromServiceSpecificException(e); } catch (SpiUnavailableException unlikely) { + // Because this function allocates a totally random SPI, it really shouldn't ever + // fail to allocate an SPI; we simply need this because the exception is checked. throw new ResourceUnavailableException("No SPIs available"); } } @@ -274,8 +297,8 @@ public final class IpSecManager { * * @param destinationAddress the destination address for traffic bearing the requested SPI. * For inbound traffic, the destination should be an address currently assigned on-device. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is - * reserved and may not be used. See RFC 4303 Section 2.1. + * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See + * RFC 4303 Section 2.1. * @return the reserved SecurityParameterIndex * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are * currently allocated for this user @@ -289,7 +312,11 @@ public final class IpSecManager { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); } - return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + try { + return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + } catch (ServiceSpecificException e) { + throw rethrowUncheckedExceptionFromServiceSpecificException(e); + } } /** @@ -424,6 +451,8 @@ public final class IpSecManager { // constructor takes control and closes the user's FD when we exit the method. try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -482,6 +511,8 @@ public final class IpSecManager { public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.removeTransportModeTransforms(pfd); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -575,6 +606,13 @@ public final class IpSecManager { mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } try { @@ -583,7 +621,6 @@ public final class IpSecManager { Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); throw e; } - mCloseGuard.close(); } /** Check that the socket was closed properly. */ @@ -600,6 +637,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("UdpEncapsulationSocket{port=") + .append(mPort) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } }; /** @@ -627,7 +675,11 @@ public final class IpSecManager { if (port == 0) { throw new IllegalArgumentException("Specified port must be a valid port number!"); } - return new UdpEncapsulationSocket(mService, port); + try { + return new UdpEncapsulationSocket(mService, port); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -650,7 +702,11 @@ public final class IpSecManager { @NonNull public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { - return new UdpEncapsulationSocket(mService, 0); + try { + return new UdpEncapsulationSocket(mService, 0); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -667,6 +723,7 @@ public final class IpSecManager { */ @SystemApi public static final class IpSecTunnelInterface implements AutoCloseable { + private final String mOpPackageName; private final IIpSecService mService; private final InetAddress mRemoteAddress; private final InetAddress mLocalAddress; @@ -688,12 +745,17 @@ public final class IpSecManager { * tunneled traffic. * * @param address the local address for traffic inside the tunnel + * @param prefixLen length of the InetAddress prefix * @hide */ @SystemApi - public void addAddress(@NonNull LinkAddress address) throws IOException { + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) + public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { - mService.addAddressToTunnelInterface(mResourceId, address); + mService.addAddressToTunnelInterface( + mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -705,21 +767,27 @@ public final class IpSecManager { *

Remove an address which was previously added to the IpSecTunnelInterface * * @param address to be removed + * @param prefixLen length of the InetAddress prefix * @hide */ @SystemApi - public void removeAddress(@NonNull LinkAddress address) throws IOException { + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) + public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { - mService.removeAddressFromTunnelInterface(mResourceId, address); + mService.removeAddressFromTunnelInterface( + mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - private IpSecTunnelInterface(@NonNull IIpSecService service, + private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service, @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { + mOpPackageName = ctx.getOpPackageName(); mService = service; mLocalAddress = localAddress; mRemoteAddress = remoteAddress; @@ -731,7 +799,8 @@ public final class IpSecManager { localAddress.getHostAddress(), remoteAddress.getHostAddress(), underlyingNetwork, - new Binder()); + new Binder(), + mOpPackageName); switch (result.status) { case Status.OK: break; @@ -760,12 +829,17 @@ public final class IpSecManager { @Override public void close() { try { - mService.deleteTunnelInterface(mResourceId); - mResourceId = INVALID_RESOURCE_ID; + mService.deleteTunnelInterface(mResourceId, mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } - mCloseGuard.close(); } /** Check that the Interface was closed properly. */ @@ -782,6 +856,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("IpSecTunnelInterface{ifname=") + .append(mInterfaceName) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } /** @@ -801,11 +886,16 @@ public final class IpSecManager { */ @SystemApi @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { - return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork); + try { + return new IpSecTunnelInterface( + mContext, mService, localAddress, remoteAddress, underlyingNetwork); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -826,12 +916,15 @@ public final class IpSecManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( - tunnel.getResourceId(), direction, transform.getResourceId()); + tunnel.getResourceId(), direction, + transform.getResourceId(), mContext.getOpPackageName()); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -843,7 +936,48 @@ public final class IpSecManager { * @param context the application context for this manager * @hide */ - public IpSecManager(IIpSecService service) { + public IpSecManager(Context ctx, IIpSecService service) { + mContext = ctx; mService = checkNotNull(service, "missing service"); } + + private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) { + // OsConstants are late binding, so switch statements can't be used. + if (sse.errorCode == OsConstants.EINVAL) { + throw new IllegalArgumentException(sse); + } else if (sse.errorCode == OsConstants.EAGAIN) { + throw new IllegalStateException(sse); + } else if (sse.errorCode == OsConstants.EOPNOTSUPP) { + throw new UnsupportedOperationException(sse); + } + } + + /** + * Convert an Errno SSE to the correct Unchecked exception type. + * + * This method never actually returns. + */ + // package + static RuntimeException + rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) { + maybeHandleServiceSpecificException(sse); + throw new RuntimeException(sse); + } + + /** + * Convert an Errno SSE to the correct Checked or Unchecked exception type. + * + * This method may throw IOException, or it may throw an unchecked exception; it will never + * actually return. + */ + // package + static IOException rethrowCheckedExceptionFromServiceSpecificException( + ServiceSpecificException sse) throws IOException { + // First see if this is an unchecked exception of a type we know. + // If so, then we prefer the unchecked (specific) type of exception. + maybeHandleServiceSpecificException(sse); + // If not, then all we can do is provide the SSE in the form of an IOException. + throw new ErrnoException( + "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException(); + } } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index cf58647bbb..23c8aa368d 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -29,6 +29,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -130,12 +131,15 @@ public final class IpSecTransform implements AutoCloseable { synchronized (this) { try { IIpSecService svc = getIpSecService(); - IpSecTransformResponse result = svc.createTransform(mConfig, new Binder()); + IpSecTransformResponse result = svc.createTransform( + mConfig, new Binder(), mContext.getOpPackageName()); int status = result.status; checkResultStatus(status); mResourceId = result.resourceId; Log.d(TAG, "Added Transform with Id " + mResourceId); mCloseGuard.open("build"); + } catch (ServiceSpecificException e) { + throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -180,6 +184,10 @@ public final class IpSecTransform implements AutoCloseable { stopNattKeepalive(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); } finally { mResourceId = INVALID_RESOURCE_ID; mCloseGuard.close(); @@ -282,7 +290,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD }) public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback, @@ -325,7 +333,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD }) public void stopNattKeepalive() { @@ -478,7 +486,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) @@ -506,4 +514,13 @@ public final class IpSecTransform implements AutoCloseable { mConfig = new IpSecConfig(); } } + + @Override + public String toString() { + return new StringBuilder() + .append("IpSecTransform{resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 35bde8e18d..744ed25f16 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -24,6 +24,8 @@ import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.NonNull; +import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.IIpSecService; @@ -42,6 +44,7 @@ import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; +import android.os.DeadSystemException; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -973,6 +976,13 @@ public class IpSecService extends IIpSecService.Stub { return service; } + @NonNull + private AppOpsManager getAppOpsManager() { + AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps"); + return appOps; + } + /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { @@ -1090,9 +1100,11 @@ public class IpSecService extends IIpSecService.Stub { new RefcountedResource( new SpiRecord(resourceId, "", destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { - // TODO: Add appropriate checks when other ServiceSpecificException types are supported - return new IpSecSpiResponse( - IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); + if (e.errorCode == OsConstants.ENOENT) { + return new IpSecSpiResponse( + IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); + } + throw e; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1104,7 +1116,6 @@ public class IpSecService extends IIpSecService.Stub { */ private void releaseResource(RefcountedResourceArray resArray, int resourceId) throws RemoteException { - resArray.getRefcountedResourceOrThrow(resourceId).userRelease(); } @@ -1239,7 +1250,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized IpSecTunnelInterfaceResponse createTunnelInterface( - String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) { + String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, + String callingPackage) { + enforceTunnelPermissions(callingPackage); checkNotNull(binder, "Null Binder passed to createTunnelInterface"); checkNotNull(underlyingNetwork, "No underlying network was specified"); checkInetAddress(localAddr); @@ -1302,15 +1315,12 @@ public class IpSecService extends IIpSecService.Stub { releaseNetId(ikey); releaseNetId(okey); throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (Throwable t) { + // Release keys if we got an error. + releaseNetId(ikey); + releaseNetId(okey); + throw t; } - - // If we make it to here, then something has gone wrong and we couldn't create a VTI. - // Release the keys that we reserved, and return an error status. - releaseNetId(ikey); - releaseNetId(okey); - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } /** @@ -1319,8 +1329,8 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void addAddressToTunnelInterface( - int tunnelResourceId, LinkAddress localAddr) { - enforceNetworkStackPermission(); + int tunnelResourceId, LinkAddress localAddr, String callingPackage) { + enforceTunnelPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1339,9 +1349,6 @@ public class IpSecService extends IIpSecService.Stub { localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. - throw new IllegalArgumentException(e); } } @@ -1351,10 +1358,10 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void removeAddressFromTunnelInterface( - int tunnelResourceId, LinkAddress localAddr) { - enforceNetworkStackPermission(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int tunnelResourceId, LinkAddress localAddr, String callingPackage) { + enforceTunnelPermissions(callingPackage); + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw // IllegalArgumentException TunnelInterfaceRecord tunnelInterfaceInfo = @@ -1371,9 +1378,6 @@ public class IpSecService extends IIpSecService.Stub { localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. - throw new IllegalArgumentException(e); } } @@ -1382,7 +1386,9 @@ public class IpSecService extends IIpSecService.Stub { * server */ @Override - public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException { + public synchronized void deleteTunnelInterface( + int resourceId, String callingPackage) throws RemoteException { + enforceTunnelPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); releaseResource(userRecord.mTunnelInterfaceRecords, resourceId); } @@ -1468,7 +1474,6 @@ public class IpSecService extends IIpSecService.Stub { case IpSecTransform.MODE_TRANSPORT: break; case IpSecTransform.MODE_TUNNEL: - enforceNetworkStackPermission(); break; default: throw new IllegalArgumentException( @@ -1476,9 +1481,24 @@ public class IpSecService extends IIpSecService.Stub { } } - private void enforceNetworkStackPermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK, - "IpSecService"); + private static final String TUNNEL_OP = "STOPSHIP"; // = AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; + + private void enforceTunnelPermissions(String callingPackage) { + checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); + if (false) { // STOPSHIP if this line is present + switch (getAppOpsManager().noteOp( + TUNNEL_OP, + Binder.getCallingUid(), callingPackage)) { + case AppOpsManager.MODE_DEFAULT: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); + break; + case AppOpsManager.MODE_ALLOWED: + return; + default: + throw new SecurityException("Request to ignore AppOps for non-legacy API"); + } + } } private void createOrUpdateTransform( @@ -1534,8 +1554,12 @@ public class IpSecService extends IIpSecService.Stub { * result in all of those sockets becoming unable to send or receive data. */ @Override - public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder) - throws RemoteException { + public synchronized IpSecTransformResponse createTransform( + IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { + checkNotNull(c); + if (c.getMode() == IpSecTransform.MODE_TUNNEL) { + enforceTunnelPermissions(callingPackage); + } checkIpSecConfig(c); checkNotNull(binder, "Null Binder passed to createTransform"); final int resourceId = mNextResourceId++; @@ -1561,12 +1585,7 @@ public class IpSecService extends IIpSecService.Stub { dependencies.add(refcountedSpiRecord); SpiRecord spiRecord = refcountedSpiRecord.getResource(); - try { - createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } + createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); // SA was created successfully, time to construct a record and lock it away userRecord.mTransformRecords.put( @@ -1613,23 +1632,15 @@ public class IpSecService extends IIpSecService.Stub { c.getMode() == IpSecTransform.MODE_TRANSPORT, "Transform mode was not Transport mode; cannot be applied to a socket"); - try { - mSrvConfig - .getNetdInstance() - .ipSecApplyTransportModeTransform( - socket.getFileDescriptor(), - resourceId, - direction, - c.getSourceAddress(), - c.getDestinationAddress(), - info.getSpiRecord().getSpi()); - } catch (ServiceSpecificException e) { - if (e.errorCode == EINVAL) { - throw new IllegalArgumentException(e.toString()); - } else { - throw e; - } - } + mSrvConfig + .getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + info.getSpiRecord().getSpi()); } /** @@ -1641,13 +1652,9 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) throws RemoteException { - try { - mSrvConfig - .getNetdInstance() - .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } + mSrvConfig + .getNetdInstance() + .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); } /** @@ -1656,8 +1663,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void applyTunnelModeTransform( - int tunnelResourceId, int direction, int transformResourceId) throws RemoteException { - enforceNetworkStackPermission(); + int tunnelResourceId, int direction, + int transformResourceId, String callingPackage) throws RemoteException { + enforceTunnelPermissions(callingPackage); checkDirection(direction); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());