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