1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package libcore.libcore.io; 18 19 import org.junit.After; 20 import org.junit.Before; 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.junit.runners.JUnit4; 24 import org.mockito.Mock; 25 import org.mockito.MockitoAnnotations; 26 27 import android.system.OsConstants; 28 import android.system.StructAddrinfo; 29 30 import java.lang.reflect.Method; 31 import java.net.InetAddress; 32 import java.util.Arrays; 33 import java.util.HashSet; 34 import java.util.List; 35 import java.util.Set; 36 import java.util.regex.Matcher; 37 import java.util.regex.Pattern; 38 39 import libcore.io.BlockGuardOs; 40 import libcore.io.Os; 41 42 import dalvik.system.BlockGuard; 43 44 import static org.junit.Assert.assertSame; 45 import static org.junit.Assert.fail; 46 import static org.mockito.ArgumentMatchers.any; 47 import static org.mockito.ArgumentMatchers.anyInt; 48 import static org.mockito.ArgumentMatchers.anyString; 49 import static org.mockito.Mockito.times; 50 import static org.mockito.Mockito.verify; 51 import static org.mockito.Mockito.when; 52 53 @RunWith(JUnit4.class) 54 public class BlockGuardOsTest { 55 56 final static Pattern pattern = Pattern.compile("[\\w\\$]+\\([^)]*\\)"); 57 58 @Mock private Os mockOsDelegate; 59 @Mock private BlockGuard.Policy mockThreadPolicy; 60 61 private BlockGuard.Policy savedThreadPolicy; 62 63 @Before 64 public void setUp() { 65 MockitoAnnotations.initMocks(this); 66 savedThreadPolicy = BlockGuard.getThreadPolicy(); 67 BlockGuard.setThreadPolicy(mockThreadPolicy); 68 } 69 70 @After 71 public void tearDown() { 72 BlockGuard.setThreadPolicy(savedThreadPolicy); 73 } 74 75 @Test 76 public void test_android_getaddrinfo_networkPolicy() { 77 InetAddress[] addresses = new InetAddress[] { InetAddress.getLoopbackAddress() }; 78 when(mockOsDelegate.android_getaddrinfo(anyString(), any(), anyInt())) 79 .thenReturn(addresses); 80 81 BlockGuardOs blockGuardOs = new BlockGuardOs(mockOsDelegate); 82 83 // Test with a numeric address that will not trigger a network policy check. 84 { 85 final String node = "numeric"; 86 final int netId = 1234; 87 final StructAddrinfo numericAddrInfo = new StructAddrinfo(); 88 numericAddrInfo.ai_flags = OsConstants.AI_NUMERICHOST; 89 InetAddress[] actual = 90 blockGuardOs.android_getaddrinfo(node, numericAddrInfo, netId); 91 92 verify(mockThreadPolicy, times(0)).onNetwork(); 93 verify(mockOsDelegate, times(1)).android_getaddrinfo(node, numericAddrInfo, netId); 94 assertSame(addresses, actual); 95 } 96 97 // Test with a non-numeric address that will trigger a network policy check. 98 { 99 final String node = "non-numeric"; 100 final int netId = 1234; 101 final StructAddrinfo nonNumericAddrInfo = new StructAddrinfo(); 102 InetAddress[] actual = 103 blockGuardOs.android_getaddrinfo(node, nonNumericAddrInfo, netId); 104 105 verify(mockThreadPolicy, times(1)).onNetwork(); 106 verify(mockOsDelegate, times(1)).android_getaddrinfo(node, nonNumericAddrInfo, netId); 107 assertSame(addresses, actual); 108 } 109 } 110 111 /** 112 * Checks that BlockGuardOs is updated when the Os interface changes. BlockGuardOs extends 113 * ForwardingOs so doing so isn't an obvious step and it can be missed. When adding methods to 114 * Os developers must give consideration to whether extra behavior should be added to 115 * BlockGuardOs. Developers failing this test should add to the list of method below 116 * (if the calls cannot block) or should add an override for the method with the appropriate 117 * calls to BlockGuard (if the calls can block). 118 */ 119 @Test 120 public void test_checkNewMethodsInPosix() { 121 List<String> methodsNotRequireBlockGuardChecks = Arrays.asList( 122 "bind(java.io.FileDescriptor,java.net.InetAddress,int)", 123 "bind(java.io.FileDescriptor,java.net.SocketAddress)", 124 "capget(android.system.StructCapUserHeader)", 125 "capset(android.system.StructCapUserHeader,android.system.StructCapUserData[])", 126 "dup(java.io.FileDescriptor)", 127 "dup2(java.io.FileDescriptor,int)", 128 "environ()", 129 "fcntlFlock(java.io.FileDescriptor,int,android.system.StructFlock)", 130 "fcntlInt(java.io.FileDescriptor,int,int)", 131 "fcntlVoid(java.io.FileDescriptor,int)", 132 "gai_strerror(int)", 133 "getegid()", 134 "getenv(java.lang.String)", 135 "geteuid()", 136 "getgid()", 137 "getgroups()", 138 "getifaddrs()", 139 "getnameinfo(java.net.InetAddress,int)", 140 "getpeername(java.io.FileDescriptor)", 141 "getpgid(int)", 142 "getpid()", 143 "getppid()", 144 "getpwnam(java.lang.String)", 145 "getpwuid(int)", 146 "getrlimit(int)", 147 "getsockname(java.io.FileDescriptor)", 148 "getsockoptByte(java.io.FileDescriptor,int,int)", 149 "getsockoptInAddr(java.io.FileDescriptor,int,int)", 150 "getsockoptInt(java.io.FileDescriptor,int,int)", 151 "getsockoptLinger(java.io.FileDescriptor,int,int)", 152 "getsockoptTimeval(java.io.FileDescriptor,int,int)", 153 "getsockoptUcred(java.io.FileDescriptor,int,int)", 154 "gettid()", 155 "getuid()", 156 "if_indextoname(int)", 157 "if_nametoindex(java.lang.String)", 158 "inet_pton(int,java.lang.String)", 159 "ioctlFlags(java.io.FileDescriptor,java.lang.String)", 160 "ioctlInetAddress(java.io.FileDescriptor,int,java.lang.String)", 161 "ioctlInt(java.io.FileDescriptor,int,android.system.Int32Ref)", 162 "ioctlMTU(java.io.FileDescriptor,java.lang.String)", 163 "isatty(java.io.FileDescriptor)", 164 "kill(int,int)", 165 "listen(java.io.FileDescriptor,int)", 166 "listxattr(java.lang.String)", 167 "mincore(long,long,byte[])", 168 "mlock(long,long)", 169 "mmap(long,long,int,int,java.io.FileDescriptor,long)", 170 "munlock(long,long)", 171 "munmap(long,long)", 172 "pipe2(int)", 173 "prctl(int,long,long,long,long)", 174 "setegid(int)", 175 "setenv(java.lang.String,java.lang.String,boolean)", 176 "seteuid(int)", 177 "setgid(int)", 178 "setgroups(int[])", 179 "setpgid(int,int)", 180 "setregid(int,int)", 181 "setreuid(int,int)", 182 "setsid()", 183 "setsockoptByte(java.io.FileDescriptor,int,int,int)", 184 "setsockoptGroupReq(java.io.FileDescriptor,int,int,android.system.StructGroupReq)", 185 "setsockoptIfreq(java.io.FileDescriptor,int,int,java.lang.String)", 186 "setsockoptInt(java.io.FileDescriptor,int,int,int)", 187 "setsockoptIpMreqn(java.io.FileDescriptor,int,int,int)", 188 "setsockoptLinger(java.io.FileDescriptor,int,int,android.system.StructLinger)", 189 "setsockoptTimeval(java.io.FileDescriptor,int,int,android.system.StructTimeval)", 190 "setuid(int)", 191 "shutdown(java.io.FileDescriptor,int)", 192 "strerror(int)", 193 "strsignal(int)", 194 "sysconf(int)", 195 "tcdrain(java.io.FileDescriptor)", 196 "tcsendbreak(java.io.FileDescriptor,int)", 197 "umask(int)", 198 "uname()", 199 "unsetenv(java.lang.String)", 200 "waitpid(int,android.system.Int32Ref,int)"); 201 Set<String> methodsNotRequiredBlockGuardCheckSet = new HashSet<>( 202 methodsNotRequireBlockGuardChecks); 203 204 Set<String> methodsInBlockGuardOs = new HashSet<>(); 205 206 // Populate the set of the public methods implemented in BlockGuardOs. 207 for (Method method : BlockGuardOs.class.getDeclaredMethods()) { 208 String methodNameAndParameters = getMethodNameAndParameters(method.toString()); 209 methodsInBlockGuardOs.add(methodNameAndParameters); 210 } 211 212 // Verify that all the methods in libcore.io.Os should either be overridden in BlockGuardOs 213 // or else they should be in the "methodsNotRequiredBlockGuardCheckSet". 214 for (Method method : Os.class.getDeclaredMethods()) { 215 String methodSignature = method.toString(); 216 String methodNameAndParameters = getMethodNameAndParameters(methodSignature); 217 if (!methodsNotRequiredBlockGuardCheckSet.contains(methodNameAndParameters) && 218 !methodsInBlockGuardOs.contains(methodNameAndParameters)) { 219 fail(methodNameAndParameters + " is not present in " 220 + "methodsNotRequiredBlockGuardCheckSet and is also not overridden in" 221 + " BlockGuardOs class. Either override the method in BlockGuardOs or" 222 + " add it in the methodsNotRequiredBlockGuardCheckSet"); 223 224 } 225 } 226 } 227 228 /** 229 * Extract method name and parameter information from the method signature. 230 * For example, for input "public void package.class.method(A,B)", the output will be 231 * "method(A,B)". 232 */ 233 private static String getMethodNameAndParameters(String methodSignature) { 234 Matcher methodPatternMatcher = pattern.matcher(methodSignature); 235 if (methodPatternMatcher.find()) { 236 return methodPatternMatcher.group(); 237 } else { 238 throw new IllegalArgumentException(methodSignature); 239 } 240 } 241 } 242