VpnTest: test getConnectionOwnerUid API

Test connection->UID resolution for both UDP and TCP connections.

Bug: 9496886
Bug: 109758967
Test: atest HostsideVpnTests
Change-Id: Ic17c64df74f65d788fd3d95a25af3c5b44946881
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 bc982ce..1ba701d 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.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 @@
         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 @@
             // 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 @@
         }
     }
 
-    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 @@
         try {
             if (expectedFrom != null) {
                 s.send(p);
+                checkConnectionOwnerUidUdp(s, true);
                 s.receive(p);
                 MoreAsserts.assertEquals(data, p.getData());
             } else {
@@ -455,7 +475,9 @@
                     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 @@
 
         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 69b07af..853668c 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 void testAppDisallowed() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed");
     }
+
+    public void testGetConnectionOwnerUidSecurity() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testGetConnectionOwnerUidSecurity");
+    }
 }