1 package android.security.cts;
2 
3 import com.android.tradefed.device.DeviceNotAvailableException;
4 import com.android.tradefed.device.ITestDevice;
5 import com.android.tradefed.testtype.DeviceTestCase;
6 
7 import java.util.Arrays;
8 import java.util.HashSet;
9 import java.util.Set;
10 
11 public class FileSystemPermissionTest extends DeviceTestCase {
12 
13    /**
14     * A reference to the device under test.
15     */
16     private ITestDevice mDevice;
17 
18     /**
19      * Used to build the find command for finding insecure file system components
20      */
21     private static final String INSECURE_DEVICE_ADB_COMMAND = "find %s -type %s -perm /o=rwx 2>/dev/null";
22 
23     @Override
setUp()24     protected void setUp() throws Exception {
25         super.setUp();
26         mDevice = getDevice();
27     }
28 
testAllBlockDevicesAreSecure()29     public void testAllBlockDevicesAreSecure() throws Exception {
30         Set<String> insecure = getAllInsecureDevicesInDirAndSubdir("/dev", "b");
31         assertTrue("Found insecure block devices: " + insecure.toString(),
32                 insecure.isEmpty());
33     }
34 
35     /**
36      * Searches for all world accessable files, note this may need sepolicy to search the desired
37      * location and stat files.
38      * @path The path to search, must be a directory.
39      * @type The type of file to search for, must be a valid find command argument to the type
40      *       option.
41      * @returns The set of insecure fs objects found.
42      */
getAllInsecureDevicesInDirAndSubdir(String path, String type)43     private Set<String> getAllInsecureDevicesInDirAndSubdir(String path, String type) throws DeviceNotAvailableException {
44 
45         String cmd = getInsecureDeviceAdbCommand(path, type);
46         String output = mDevice.executeShellCommand(cmd);
47         // Splitting an empty string results in an array of an empty string.
48         String [] found = output.length() > 0 ? output.split("\\s") : new String[0];
49         return new HashSet<String>(Arrays.asList(found));
50     }
51 
getInsecureDeviceAdbCommand(String path, String type)52     private static String getInsecureDeviceAdbCommand(String path, String type) {
53         return String.format(INSECURE_DEVICE_ADB_COMMAND, path, type);
54     }
55 
56     private static String HW_RNG_DEVICE = "/dev/hw_random";
57 
testDevHwRandomPermissions()58     public void testDevHwRandomPermissions() throws Exception {
59         if (!mDevice.doesFileExist(HW_RNG_DEVICE)) {
60             // Hardware RNG device is missing. This is OK because it is not required to be exposed
61             // on all devices.
62             return;
63         }
64 
65         // This test asserts that, if present, /dev/hw_random must:
66         //
67         // 1. Have ownership prng_seeder:prng_seeder
68         // 2. Have permissions 0400 - The only user space process requiring
69         //    access is the PRNG seeder daemon which only needs read access.
70         // 3. Be a character device with major:minor 10:183 (the kernel
71         //    default).
72 
73         // That translates to `ls -l` output like this:
74         // cr-------- 1 prng_seeder prng_seeder 10, 183 2021-02-11 17:55 /dev/hw_random
75 
76         String command = "ls -l " + HW_RNG_DEVICE;
77         String output = mDevice.executeShellCommand(command).trim();
78         if (!output.endsWith(" " + HW_RNG_DEVICE)) {
79             fail("Unexpected output from " + command + ": \"" + output + "\"");
80         }
81         String[] outputWords = output.split("\\s");
82         assertEquals("Wrong mode on " + HW_RNG_DEVICE, "cr--------", outputWords[0]);
83         assertEquals("Wrong owner of " + HW_RNG_DEVICE, "prng_seeder", outputWords[2]);
84         assertEquals("Wrong group of " + HW_RNG_DEVICE, "prng_seeder", outputWords[3]);
85         assertEquals("Wrong device major on " + HW_RNG_DEVICE, "10,", outputWords[4]);
86         assertEquals("Wrong device minor on " + HW_RNG_DEVICE, "183", outputWords[5]);
87     }
88 }
89