Home | History | Annotate | Download | only in io
      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