diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index bc982cec78..1ba701de29 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside; +import static android.os.Process.INVALID_UID; import static android.system.OsConstants.*; import android.content.Intent; @@ -36,6 +37,7 @@ import android.support.test.uiautomator.UiScrollable; import android.support.test.uiautomator.UiSelector; import android.system.ErrnoException; import android.system.Os; +import android.system.OsConstants; import android.system.StructPollfd; import android.test.InstrumentationTestCase; import android.test.MoreAsserts; @@ -353,7 +355,7 @@ public class VpnTest extends InstrumentationTestCase { MoreAsserts.assertEquals(data, read); } - private static void checkTcpReflection(String to, String expectedFrom) throws IOException { + private void checkTcpReflection(String to, String expectedFrom) throws IOException { // Exercise TCP over the VPN by "connecting to ourselves". We open a server socket and a // client socket, and connect the client socket to a remote host, with the port of the // server socket. The PacketReflector reflects the packets, changing the source addresses @@ -391,7 +393,8 @@ public class VpnTest extends InstrumentationTestCase { // Accept the connection on the server side. listen.setSoTimeout(SOCKET_TIMEOUT_MS); server = listen.accept(); - + checkConnectionOwnerUidTcp(client); + checkConnectionOwnerUidTcp(server); // Check that the source and peer addresses are as expected. assertEquals(expectedFrom, client.getLocalAddress().getHostAddress()); assertEquals(expectedFrom, server.getLocalAddress().getHostAddress()); @@ -424,7 +427,23 @@ public class VpnTest extends InstrumentationTestCase { } } - private static void checkUdpEcho(String to, String expectedFrom) throws IOException { + private void checkConnectionOwnerUidUdp(DatagramSocket s, boolean expectSuccess) { + final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID; + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_UDP, loc, rem); + assertEquals(expectedUid, uid); + } + + private void checkConnectionOwnerUidTcp(Socket s) { + final int expectedUid = Process.myUid(); + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem); + assertEquals(expectedUid, uid); + } + + private void checkUdpEcho(String to, String expectedFrom) throws IOException { DatagramSocket s; InetAddress address = InetAddress.getByName(to); if (address instanceof Inet6Address) { // http://b/18094870 @@ -448,6 +467,7 @@ public class VpnTest extends InstrumentationTestCase { try { if (expectedFrom != null) { s.send(p); + checkConnectionOwnerUidUdp(s, true); s.receive(p); MoreAsserts.assertEquals(data, p.getData()); } else { @@ -455,7 +475,9 @@ public class VpnTest extends InstrumentationTestCase { s.send(p); s.receive(p); fail("Received unexpected reply"); - } catch(IOException expected) {} + } catch (IOException expected) { + checkConnectionOwnerUidUdp(s, false); + } } } finally { s.close(); @@ -580,4 +602,23 @@ public class VpnTest extends InstrumentationTestCase { checkNoTrafficOnVpn(); } + + public void testGetConnectionOwnerUidSecurity() throws Exception { + + if (!supportedHardware()) return; + + DatagramSocket s; + InetAddress address = InetAddress.getByName("localhost"); + s = new DatagramSocket(); + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(address, 7); + InetSocketAddress loc = new InetSocketAddress(s.getLocalAddress(), s.getLocalPort()); + InetSocketAddress rem = new InetSocketAddress(s.getInetAddress(), s.getPort()); + try { + int uid = mCM.getConnectionOwnerUid(OsConstants.IPPROTO_TCP, loc, rem); + fail("Only an active VPN app may call this API."); + } catch (SecurityException expected) { + return; + } + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index 69b07af193..853668c719 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -44,4 +44,8 @@ public class HostsideVpnTests extends HostsideNetworkTestCase { public void testAppDisallowed() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed"); } + + public void testGetConnectionOwnerUidSecurity() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testGetConnectionOwnerUidSecurity"); + } }