1 /*
2 * Copyright (C) 2015 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 "fscrypt/fscrypt.h"
18
19 #include <array>
20
21 #include <asm/ioctl.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <linux/fs.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/syscall.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31
32 #include <android-base/file.h>
33 #include <android-base/logging.h>
34 #include <cutils/properties.h>
35 #include <logwrap/logwrap.h>
36 #include <utils/misc.h>
37
38 #define FS_KEY_DESCRIPTOR_SIZE_HEX (2 * FS_KEY_DESCRIPTOR_SIZE + 1)
39
40 /* modes not supported by upstream kernel, so not in <linux/fs.h> */
41 #define FS_ENCRYPTION_MODE_AES_256_HEH 126
42 #define FS_ENCRYPTION_MODE_PRIVATE 127
43
44 /* new definition, not yet in Bionic's <linux/fs.h> */
45 #ifndef FS_ENCRYPTION_MODE_ADIANTUM
46 #define FS_ENCRYPTION_MODE_ADIANTUM 9
47 #endif
48
49 /* new definition, not yet in Bionic's <linux/fs.h> */
50 #ifndef FS_POLICY_FLAG_DIRECT_KEY
51 #define FS_POLICY_FLAG_DIRECT_KEY 0x4
52 #endif
53
54 #define HEX_LOOKUP "0123456789abcdef"
55
fscrypt_is_native()56 bool fscrypt_is_native() {
57 char value[PROPERTY_VALUE_MAX];
58 property_get("ro.crypto.type", value, "none");
59 return !strcmp(value, "file");
60 }
61
log_ls(const char * dirname)62 static void log_ls(const char* dirname) {
63 std::array<const char*, 3> argv = {"ls", "-laZ", dirname};
64 int status = 0;
65 auto res =
66 android_fork_execvp(argv.size(), const_cast<char**>(argv.data()), &status, false, true);
67 if (res != 0) {
68 PLOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] << "failed";
69 return;
70 }
71 if (!WIFEXITED(status)) {
72 LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2]
73 << " did not exit normally, status: " << status;
74 return;
75 }
76 if (WEXITSTATUS(status) != 0) {
77 LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2]
78 << " returned failure: " << WEXITSTATUS(status);
79 return;
80 }
81 }
82
policy_to_hex(const char * policy,char * hex)83 static void policy_to_hex(const char* policy, char* hex) {
84 for (size_t i = 0, j = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++) {
85 hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4];
86 hex[j++] = HEX_LOOKUP[policy[i] & 0x0F];
87 }
88 hex[FS_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0';
89 }
90
is_dir_empty(const char * dirname,bool * is_empty)91 static bool is_dir_empty(const char *dirname, bool *is_empty)
92 {
93 int n = 0;
94 auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(dirname), closedir);
95 if (!dirp) {
96 PLOG(ERROR) << "Unable to read directory: " << dirname;
97 return false;
98 }
99 for (;;) {
100 errno = 0;
101 auto entry = readdir(dirp.get());
102 if (!entry) {
103 if (errno) {
104 PLOG(ERROR) << "Unable to read directory: " << dirname;
105 return false;
106 }
107 break;
108 }
109 if (strcmp(entry->d_name, "lost+found") != 0) { // Skip lost+found
110 ++n;
111 if (n > 2) {
112 *is_empty = false;
113 return true;
114 }
115 }
116 }
117 *is_empty = true;
118 return true;
119 }
120
fscrypt_get_policy_flags(int filenames_encryption_mode)121 static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode) {
122 if (filenames_encryption_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
123 // Use legacy padding with our original filenames encryption mode.
124 return FS_POLICY_FLAGS_PAD_4;
125 } else if (filenames_encryption_mode == FS_ENCRYPTION_MODE_ADIANTUM) {
126 // Use DIRECT_KEY for Adiantum, since it's much more efficient but just
127 // as secure since Android doesn't reuse the same master key for
128 // multiple encryption modes
129 return (FS_POLICY_FLAGS_PAD_16 | FS_POLICY_FLAG_DIRECT_KEY);
130 }
131 // With a new mode we can use the better padding flag without breaking existing devices: pad
132 // filenames with zeroes to the next 16-byte boundary. This is more secure (helps hide the
133 // length of filenames) and makes the inputs evenly divisible into blocks which is more
134 // efficient for encryption and decryption.
135 return FS_POLICY_FLAGS_PAD_16;
136 }
137
fscrypt_policy_set(const char * directory,const char * policy,size_t policy_length,int contents_encryption_mode,int filenames_encryption_mode)138 static bool fscrypt_policy_set(const char *directory, const char *policy,
139 size_t policy_length,
140 int contents_encryption_mode,
141 int filenames_encryption_mode) {
142 if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
143 LOG(ERROR) << "Policy wrong length: " << policy_length;
144 return false;
145 }
146 char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
147 policy_to_hex(policy, policy_hex);
148
149 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
150 if (fd == -1) {
151 PLOG(ERROR) << "Failed to open directory " << directory;
152 return false;
153 }
154
155 fscrypt_policy fp;
156 fp.version = 0;
157 fp.contents_encryption_mode = contents_encryption_mode;
158 fp.filenames_encryption_mode = filenames_encryption_mode;
159 fp.flags = fscrypt_get_policy_flags(filenames_encryption_mode);
160 memcpy(fp.master_key_descriptor, policy, FS_KEY_DESCRIPTOR_SIZE);
161 if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &fp)) {
162 PLOG(ERROR) << "Failed to set encryption policy for " << directory << " to " << policy_hex
163 << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode;
164 close(fd);
165 return false;
166 }
167 close(fd);
168
169 LOG(INFO) << "Policy for " << directory << " set to " << policy_hex
170 << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode;
171 return true;
172 }
173
fscrypt_policy_get(const char * directory,char * policy,size_t policy_length,int contents_encryption_mode,int filenames_encryption_mode)174 static bool fscrypt_policy_get(const char *directory, char *policy,
175 size_t policy_length,
176 int contents_encryption_mode,
177 int filenames_encryption_mode) {
178 if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
179 LOG(ERROR) << "Policy wrong length: " << policy_length;
180 return false;
181 }
182
183 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
184 if (fd == -1) {
185 PLOG(ERROR) << "Failed to open directory " << directory;
186 return false;
187 }
188
189 fscrypt_policy fp;
190 memset(&fp, 0, sizeof(fscrypt_policy));
191 if (ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &fp) != 0) {
192 PLOG(ERROR) << "Failed to get encryption policy for " << directory;
193 close(fd);
194 log_ls(directory);
195 return false;
196 }
197 close(fd);
198
199 if ((fp.version != 0)
200 || (fp.contents_encryption_mode != contents_encryption_mode)
201 || (fp.filenames_encryption_mode != filenames_encryption_mode)
202 || (fp.flags !=
203 fscrypt_get_policy_flags(filenames_encryption_mode))) {
204 LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
205 return false;
206 }
207 memcpy(policy, fp.master_key_descriptor, FS_KEY_DESCRIPTOR_SIZE);
208
209 return true;
210 }
211
fscrypt_policy_check(const char * directory,const char * policy,size_t policy_length,int contents_encryption_mode,int filenames_encryption_mode)212 static bool fscrypt_policy_check(const char *directory, const char *policy,
213 size_t policy_length,
214 int contents_encryption_mode,
215 int filenames_encryption_mode) {
216 if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
217 LOG(ERROR) << "Policy wrong length: " << policy_length;
218 return false;
219 }
220 char existing_policy[FS_KEY_DESCRIPTOR_SIZE];
221 if (!fscrypt_policy_get(directory, existing_policy, FS_KEY_DESCRIPTOR_SIZE,
222 contents_encryption_mode,
223 filenames_encryption_mode)) return false;
224 char existing_policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
225
226 policy_to_hex(existing_policy, existing_policy_hex);
227
228 if (memcmp(policy, existing_policy, FS_KEY_DESCRIPTOR_SIZE) != 0) {
229 char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
230 policy_to_hex(policy, policy_hex);
231 LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory
232 << " which doesn't match expected value " << policy_hex;
233 log_ls(directory);
234 return false;
235 }
236 LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory
237 << " which matches expected value";
238 return true;
239 }
240
fscrypt_policy_ensure(const char * directory,const char * policy,size_t policy_length,const char * contents_encryption_mode,const char * filenames_encryption_mode)241 int fscrypt_policy_ensure(const char *directory, const char *policy,
242 size_t policy_length,
243 const char *contents_encryption_mode,
244 const char *filenames_encryption_mode) {
245 int contents_mode = 0;
246 int filenames_mode = 0;
247
248 if (!strcmp(contents_encryption_mode, "software") ||
249 !strcmp(contents_encryption_mode, "aes-256-xts")) {
250 contents_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
251 } else if (!strcmp(contents_encryption_mode, "adiantum")) {
252 contents_mode = FS_ENCRYPTION_MODE_ADIANTUM;
253 } else if (!strcmp(contents_encryption_mode, "ice")) {
254 contents_mode = FS_ENCRYPTION_MODE_PRIVATE;
255 } else {
256 LOG(ERROR) << "Invalid file contents encryption mode: "
257 << contents_encryption_mode;
258 return -1;
259 }
260
261 if (!strcmp(filenames_encryption_mode, "aes-256-cts")) {
262 filenames_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
263 } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
264 filenames_mode = FS_ENCRYPTION_MODE_AES_256_HEH;
265 } else if (!strcmp(filenames_encryption_mode, "adiantum")) {
266 filenames_mode = FS_ENCRYPTION_MODE_ADIANTUM;
267 } else {
268 LOG(ERROR) << "Invalid file names encryption mode: "
269 << filenames_encryption_mode;
270 return -1;
271 }
272
273 bool is_empty;
274 if (!is_dir_empty(directory, &is_empty)) return -1;
275 if (is_empty) {
276 if (!fscrypt_policy_set(directory, policy, policy_length,
277 contents_mode, filenames_mode)) return -1;
278 } else {
279 if (!fscrypt_policy_check(directory, policy, policy_length,
280 contents_mode, filenames_mode)) return -1;
281 }
282 return 0;
283 }
284