• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 #include <android-base/properties.h>
18 #include <android-base/unique_fd.h>
19 #include <cutils/properties.h>
20 #include <fcntl.h>
21 #include <fscrypt/fscrypt.h>
22 #include <gtest/gtest.h>
23 #include <linux/fscrypt.h>
24 #include <setjmp.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <unistd.h>
29 
30 #include "utils.h"
31 
32 // Non-upstream encryption modes that are used on some devices.
33 #define FSCRYPT_MODE_AES_256_HEH 126
34 #define FSCRYPT_MODE_PRIVATE 127
35 
36 #ifdef __arm__
37 // For ARM32, assemble the 'aese.8' instruction as an .inst, since otherwise
38 // clang does not accept it.  It would be allowed in a separate file compiled
39 // with -march=armv8+crypto, but this way is much easier.  And it's not yet
40 // possible to use a target function attribute, because clang doesn't yet
41 // support target("fpu=crypto-neon-fp-armv8") like gcc does.
42 //
43 // We use the ARM encoding of the instruction, not the Thumb encoding.  So make
44 // sure to use target("arm") to mark the function as containing ARM code.
executeAESInstruction(void)45 static void __attribute__((target("arm"))) executeAESInstruction(void) {
46     // aese.8  q0, q1
47     asm volatile(".inst  0xf3b00302" : : : "q0");
48 }
49 #elif defined(__aarch64__)
executeAESInstruction(void)50 static void __attribute__((target("crypto"))) executeAESInstruction(void) {
51     asm volatile("aese  v0.16b, v1.16b" : : : "v0");
52 }
53 #elif defined(__i386__) || defined(__x86_64__)
executeAESInstruction(void)54 static void __attribute__((target("sse"))) executeAESInstruction(void) {
55     asm volatile("aesenc %%xmm1, %%xmm0" : : : "xmm0");
56 }
57 #else
58 // For unknown architectures, we cannot confirm that AES instructions are
59 // unsupported.  So, assume they are supported, i.e. don't raise SIGILL.  This
60 // disallows Adiantum until code is explicitly added for the architecture.
61 #warning "unknown architecture, assuming Adiantum is not allowed"
executeAESInstruction(void)62 static void executeAESInstruction(void) {}
63 #endif
64 
65 static jmp_buf jump_buf;
66 
handleSIGILL(int signum)67 static void handleSIGILL(int __attribute__((unused)) signum) {
68     longjmp(jump_buf, 1);
69 }
70 
71 // Checks whether Adiantum encryption is allowed.  Adiantum encryption is
72 // allowed only when the CPU does *not* support AES instructions.
73 //
74 // ARM processors don't have a standard way for user processes to determine CPU
75 // features.  On Linux it's possible to read the AT_HWCAP and AT_HWCAP2 values
76 // from /proc/self/auxv.  But, this relies on the kernel exposing the features
77 // correctly, which we don't want to rely on.  Instead we actually try to
78 // execute the instruction, and see whether SIGILL is raised or not.
79 //
80 // To keep things consistent we use the same approach on x86 to detect AES-NI,
81 // though in principle the 'cpuid' instruction could be used there.
isAdiantumEncryptionAllowed(void)82 static bool isAdiantumEncryptionAllowed(void) {
83     struct sigaction act;
84     struct sigaction oldact;
85     bool allowed;
86 
87     memset(&act, 0, sizeof(act));
88     act.sa_handler = handleSIGILL;
89 
90     EXPECT_EQ(0, sigaction(SIGILL, &act, &oldact));
91 
92     if (setjmp(jump_buf) != 0) {
93         // Trying to execute an AES instruction raised SIGILL, which shows that
94         // AES instructions are unsupported.  Thus, Adiantum is allowed.
95         allowed = true;
96     } else {
97         executeAESInstruction();
98         // Either an AES instruction was successfully executed, or the
99         // architecture is unknown.  So, it has *not* been shown that AES
100         // instructions are unsupported.  Thus, Adiantum is *not* allowed.
101         allowed = false;
102     }
103 
104     EXPECT_EQ(0, sigaction(SIGILL, &oldact, NULL));
105 
106     return allowed;
107 }
108 
109 // CDD 9.9.3/C-1-5: must use AES-256-XTS or Adiantum contents encryption.
110 // CDD 9.9.3/C-1-6: must use AES-256-CTS, AES-256-HCTR2, or Adiantum filenames encryption.
111 // CDD 9.9.3/C-1-12: mustn't use Adiantum if the CPU has AES instructions.
validateEncryptionModes(int contents_mode,int filenames_mode,bool allow_legacy_modes)112 static void validateEncryptionModes(int contents_mode, int filenames_mode,
113                                     bool allow_legacy_modes) {
114     bool allowed = false;
115     switch (contents_mode) {
116         case FSCRYPT_MODE_AES_256_XTS:
117         case FSCRYPT_MODE_ADIANTUM:
118             allowed = true;
119             break;
120         case FSCRYPT_MODE_PRIVATE:
121             // Some devices shipped with custom kernel patches implementing
122             // AES-256-XTS inline encryption behind "FSCRYPT_MODE_PRIVATE", so
123             // we need to let it pass on old devices.  It's up to the vendor to
124             // ensure it's really AES-256-XTS.
125             allowed = allow_legacy_modes;
126             if (allowed) {
127                 GTEST_LOG_(INFO) << "Allowing FSCRYPT_MODE_PRIVATE because this is an old device";
128             }
129             break;
130     }
131     if (!allowed) {
132         ADD_FAILURE() << "Contents encryption mode not allowed: " << contents_mode;
133     }
134 
135     allowed = false;
136     switch (filenames_mode) {
137         case FSCRYPT_MODE_AES_256_CTS:
138         case FSCRYPT_MODE_AES_256_HCTR2:
139         case FSCRYPT_MODE_ADIANTUM:
140             allowed = true;
141             break;
142         case FSCRYPT_MODE_AES_256_HEH:
143             // At least one device shipped with the experimental AES-256-HEH
144             // filenames encryption, which was never added to the CDD and was
145             // only supported by one kernel version (android-4.4).  It's
146             // cryptographically superior to AES-256-CTS for the use case,
147             // though, so it's compliant in spirit; let it pass on old devices.
148             allowed = allow_legacy_modes;
149             if (allowed) {
150                 GTEST_LOG_(INFO)
151                         << "Allowing FSCRYPT_MODE_AES_256_HEH because this is an old device";
152             }
153             break;
154     }
155     if (!allowed) {
156         ADD_FAILURE() << "Filenames encryption mode not allowed: " << filenames_mode;
157     }
158 
159     if (contents_mode == FSCRYPT_MODE_ADIANTUM || filenames_mode == FSCRYPT_MODE_ADIANTUM) {
160         EXPECT_TRUE(isAdiantumEncryptionAllowed());
161     }
162 }
163 
164 // Ideally we'd check whether /data is on eMMC, but that is hard to do from a
165 // CTS test.  To keep things simple we just check whether the system knows about
166 // at least one eMMC device.
167 //
168 // virtio devices may provide inline encryption support that is backed by eMMC
169 // inline encryption on the host, thus inheriting the DUN size limitation.  So
170 // virtio devices must be allowed here too.  TODO(b/207390665): check the
171 // maximum DUN size directly instead.
mightBeUsingEmmcStorage()172 static bool mightBeUsingEmmcStorage() {
173     struct stat stbuf;
174     return lstat("/sys/class/block/mmcblk0", &stbuf) == 0 ||
175             lstat("/sys/class/block/vda", &stbuf) == 0;
176 }
177 
178 // CDD 9.9.3/C-1-15: must not reuse IVs for file contents encryption except when
179 // limited by hardware that only supports 32-bit IVs.  Like most other
180 // encryption security requirements, CTS can't directly test this.  But the most
181 // likely case where this requirement wouldn't be met is a misconfiguration
182 // where FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ("emmc_optimized" in the fstab) is
183 // used on a non-eMMC based device.  CTS can test for that, so we do so below.
validateEncryptionFlags(int flags,bool is_adoptable_storage)184 static void validateEncryptionFlags(int flags, bool is_adoptable_storage) {
185     if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
186         EXPECT_TRUE(mightBeUsingEmmcStorage());
187         EXPECT_FALSE(is_adoptable_storage);
188     }
189 }
190 
191 // We check the encryption policy of /data/local/tmp because it's one of the
192 // only encrypted directories the shell domain has permission to open.  Ideally
193 // we'd check the user's credential-encrypted storage (/data/user/0) instead.
194 // It shouldn't matter in practice though, since AOSP code doesn't provide any
195 // way to configure different directories to use different algorithms...
196 #define DIR_TO_CHECK "/data/local/tmp/"
197 
loggedGetProperty(const std::string & name,const std::string & default_value)198 static std::string loggedGetProperty(const std::string &name, const std::string &default_value) {
199     auto value = android::base::GetProperty(name, "");
200     if (value == "" && default_value != "") {
201         GTEST_LOG_(INFO) << name << "=\"\" [defaults to \"" << default_value << "\"]";
202         return default_value;
203     }
204     GTEST_LOG_(INFO) << name << "=\"" << value << "\"";
205     return value;
206 }
207 
validateAdoptableStorageSettings(int first_api_level)208 static void validateAdoptableStorageSettings(int first_api_level) {
209     GTEST_LOG_(INFO) << "Validating FBE settings for adoptable storage";
210 
211     // Determine the options string being used.  This matches the logic in vold.
212     auto contents_mode = loggedGetProperty("ro.crypto.volume.contents_mode", "");
213     auto filenames_mode =
214             loggedGetProperty("ro.crypto.volume.filenames_mode",
215                               first_api_level > __ANDROID_API_Q__ ? "" : "aes-256-heh");
216     auto options_string =
217             loggedGetProperty("ro.crypto.volume.options", contents_mode + ":" + filenames_mode);
218 
219     // Parse the options string.
220     android::fscrypt::EncryptionOptions options;
221     ASSERT_TRUE(android::fscrypt::ParseOptions(options_string, &options));
222 
223     // Log the full options for debugging purposes.
224     std::string options_string_full;
225     ASSERT_TRUE(android::fscrypt::OptionsToString(options, &options_string_full));
226     GTEST_LOG_(INFO) << "options_string_full=\"" << options_string_full << "\"";
227 
228     // Validate the encryption options.
229     if (first_api_level > __ANDROID_API_Q__) {
230         // CDD 9.9.3/C-1-13 and 9.9.3/C-1-14, same as internal storage.
231         EXPECT_EQ(2, options.version);
232     }
233     validateEncryptionModes(options.contents_mode, options.filenames_mode, options.version == 1);
234     validateEncryptionFlags(options.flags, true);
235 }
236 
237 // Test that the device is using appropriate settings for file-based encryption.
238 // If this test fails, you should ensure that the device's fstab has the correct
239 // fileencryption= option for the userdata partition and that the ro.crypto
240 // system properties have been set to the correct values.  See
241 // https://source.android.com/security/encryption/file-based.html
242 //
243 // @CddTest = 9.9.2/C-0-3|9.9.3/C-1-5,C-1-6,C-1-12,C-1-13,C-1-14,C-1-15
TEST(FileBasedEncryptionPolicyTest,allowedPolicy)244 TEST(FileBasedEncryptionPolicyTest, allowedPolicy) {
245     int first_api_level = getFirstApiLevel();
246     int vendor_api_level = getVendorApiLevel();
247     struct fscrypt_get_policy_ex_arg arg;
248     int res;
249     int contents_mode;
250     int filenames_mode;
251     int flags;
252     bool allow_legacy_modes = false;
253 
254     std::string crypto_type = loggedGetProperty("ro.crypto.type", "");
255     GTEST_LOG_(INFO) << "First API level is " << first_api_level;
256     GTEST_LOG_(INFO) << "Vendor API level is " << vendor_api_level;
257 
258     // This feature name check only applies to devices that first shipped with
259     // SC or later.
260     int min_api_level = (first_api_level < vendor_api_level) ? first_api_level
261                                                              : vendor_api_level;
262     if (min_api_level >= __ANDROID_API_S__ &&
263         !deviceSupportsFeature("android.hardware.security.model.compatible")) {
264         GTEST_SKIP()
265             << "Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.";
266         return;
267     }
268 
269     GTEST_LOG_(INFO) << "Validating FBE settings for internal storage";
270 
271     android::base::unique_fd fd(open(DIR_TO_CHECK, O_RDONLY | O_CLOEXEC));
272     if (fd < 0) {
273         FAIL() << "Failed to open " DIR_TO_CHECK ": " << strerror(errno);
274     }
275 
276     // Note: SELinux policy allows the shell domain to use these ioctls, but not
277     // apps.  Therefore this test needs to be a real native test that's run
278     // through the shell, not a JNI test run through an installed APK.
279     arg.policy_size = sizeof(arg.policy);
280     res = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
281     if (res != 0 && errno == ENOTTY) {
282         // Handle old kernels that don't support FS_IOC_GET_ENCRYPTION_POLICY_EX
283         GTEST_LOG_(INFO) << "Old kernel, falling back to FS_IOC_GET_ENCRYPTION_POLICY";
284         res = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &arg.policy.v1);
285     }
286     if (res != 0) {
287         if (errno == ENODATA ||     // Directory is unencrypted
288             errno == ENOENT ||      // Directory is unencrypted (on older kernels)
289             errno == EOPNOTSUPP ||  // Filesystem encryption feature not enabled
290             errno == ENOTTY) {      // Very old kernel, doesn't know about encryption at all
291 
292             // Starting with Android 10, file-based encryption is required on
293             // new devices [CDD 9.9.2/C-0-3].
294             if (first_api_level < __ANDROID_API_Q__) {
295                 GTEST_LOG_(INFO)
296                         << "Exempt from file-based encryption due to old starting API level";
297                 return;
298             }
299             if (crypto_type == "managed") {
300                 // Android is running in a virtualized environment and the file system is encrypted
301                 // by the host system.
302                 GTEST_LOG_(INFO) << "Exempt from file-based encryption because the file system is "
303                                  << "encrypted by the host system";
304                 // Note: All encryption-related CDD requirements still must be met,
305                 // but they can't be tested directly in this case.
306                 return;
307             }
308             FAIL() << "Device isn't using file-based encryption";
309         } else {
310             FAIL() << "Failed to get encryption policy of " DIR_TO_CHECK ": " << strerror(errno);
311         }
312     }
313 
314     switch (arg.policy.version) {
315         case FSCRYPT_POLICY_V1:
316             GTEST_LOG_(INFO) << "Detected v1 encryption policy";
317             contents_mode = arg.policy.v1.contents_encryption_mode;
318             filenames_mode = arg.policy.v1.filenames_encryption_mode;
319             flags = arg.policy.v1.flags;
320 
321             // Starting with Android 11, FBE must use a strong, non-reversible
322             // key derivation function [CDD 9.9.3/C-1-13], and FBE keys must
323             // never be never reused for different cryptographic purposes
324             // [CDD 9.9.3/C-1-14].  Effectively, these requirements mean that
325             // the fscrypt policy version must not be v1.  If this part of the
326             // test fails, make sure the device's fstab doesn't contain the "v1"
327             // flag in the argument to the fileencryption option.
328             if (first_api_level < __ANDROID_API_R__) {
329                 GTEST_LOG_(INFO) << "Exempt from non-reversible FBE key derivation due to old "
330                                     "starting API level";
331                 // On these old devices we also allow the use of some custom
332                 // encryption mode numbers which were never supported by the
333                 // Android common kernel and shouldn't be used on new devices.
334                 allow_legacy_modes = true;
335             } else {
336                 ADD_FAILURE() << "Device isn't using non-reversible FBE key derivation";
337             }
338             break;
339         case FSCRYPT_POLICY_V2:
340             GTEST_LOG_(INFO) << "Detected v2 encryption policy";
341             contents_mode = arg.policy.v2.contents_encryption_mode;
342             filenames_mode = arg.policy.v2.filenames_encryption_mode;
343             flags = arg.policy.v2.flags;
344             break;
345         default:
346             FAIL() << "Unknown encryption policy version: " << arg.policy.version;
347     }
348 
349     GTEST_LOG_(INFO) << "Contents encryption mode: " << contents_mode;
350     GTEST_LOG_(INFO) << "Filenames encryption mode: " << filenames_mode;
351 
352     validateEncryptionModes(contents_mode, filenames_mode, allow_legacy_modes);
353     validateEncryptionFlags(flags, false);
354 
355     validateAdoptableStorageSettings(first_api_level);
356 }
357