blob: adeb66aa3cb31db9f1d3864c06ef5a91069073cc [file] [log] [blame]
Paul Lawrence377cd192015-04-28 22:13:04 +00001/*
Paul Crowley8d53b962016-04-27 10:24:40 -07002 * 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.
Paul Lawrence377cd192015-04-28 22:13:04 +000015 */
16
Eric Biggersb46c3592018-10-23 13:39:07 -070017#include "fscrypt/fscrypt.h"
Paul Lawrence92da49d2015-02-25 15:11:13 -080018
Paul Crowleyc4547882018-05-16 13:41:01 -070019#include <array>
20
Tao Bao06ca8112016-10-05 12:44:18 -070021#include <asm/ioctl.h>
Paul Lawrence4818b732016-05-23 22:03:40 +000022#include <dirent.h>
23#include <errno.h>
Paul Lawrence4818b732016-05-23 22:03:40 +000024#include <fcntl.h>
Eric Biggersb0ff8832018-10-23 13:39:07 -070025#include <linux/fs.h>
Tao Bao06ca8112016-10-05 12:44:18 -070026#include <string.h>
Paul Lawrence4818b732016-05-23 22:03:40 +000027#include <sys/stat.h>
Eric Biggersb0ff8832018-10-23 13:39:07 -070028#include <sys/syscall.h>
Paul Lawrence4818b732016-05-23 22:03:40 +000029#include <sys/types.h>
Tao Bao06ca8112016-10-05 12:44:18 -070030#include <unistd.h>
Paul Lawrence4818b732016-05-23 22:03:40 +000031
Paul Lawrencec096c9c2016-05-24 04:57:23 -070032#include <android-base/file.h>
Paul Lawrence4818b732016-05-23 22:03:40 +000033#include <android-base/logging.h>
Paul Crowley8d53b962016-04-27 10:24:40 -070034#include <cutils/properties.h>
Paul Crowleyc4547882018-05-16 13:41:01 -070035#include <logwrap/logwrap.h>
36#include <utils/misc.h>
Paul Lawrence92da49d2015-02-25 15:11:13 -080037
Eric Biggersb0ff8832018-10-23 13:39:07 -070038#define FS_KEY_DESCRIPTOR_SIZE_HEX (2 * FS_KEY_DESCRIPTOR_SIZE + 1)
Paul Lawrence4818b732016-05-23 22:03:40 +000039
Eric Biggersb0ff8832018-10-23 13:39:07 -070040/* modes not supported by upstream kernel, so not in <linux/fs.h> */
Eric Biggersb46c3592018-10-23 13:39:07 -070041#define FS_ENCRYPTION_MODE_AES_256_HEH 126
42#define FS_ENCRYPTION_MODE_PRIVATE 127
Paul Lawrence4818b732016-05-23 22:03:40 +000043
Greg Kaiserb46c11c2018-12-03 12:36:56 -080044/* 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
Paul Lawrence4818b732016-05-23 22:03:40 +000054#define HEX_LOOKUP "0123456789abcdef"
55
Eric Biggersb46c3592018-10-23 13:39:07 -070056bool fscrypt_is_native() {
Paul Crowley8d53b962016-04-27 10:24:40 -070057 char value[PROPERTY_VALUE_MAX];
58 property_get("ro.crypto.type", value, "none");
59 return !strcmp(value, "file");
60}
Paul Lawrence4818b732016-05-23 22:03:40 +000061
Paul Crowleye1f6ad42018-05-22 15:58:38 -070062static void log_ls(const char* dirname) {
63 std::array<const char*, 3> argv = {"ls", "-laZ", dirname};
Paul Crowleyc4547882018-05-16 13:41:01 -070064 int status = 0;
65 auto res =
66 android_fork_execvp(argv.size(), const_cast<char**>(argv.data()), &status, false, true);
67 if (res != 0) {
Paul Crowleye1f6ad42018-05-22 15:58:38 -070068 PLOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] << "failed";
Paul Crowleyc4547882018-05-16 13:41:01 -070069 return;
70 }
71 if (!WIFEXITED(status)) {
Paul Crowleye1f6ad42018-05-22 15:58:38 -070072 LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2]
73 << " did not exit normally, status: " << status;
Paul Crowleyc4547882018-05-16 13:41:01 -070074 return;
75 }
76 if (WEXITSTATUS(status) != 0) {
Paul Crowleye1f6ad42018-05-22 15:58:38 -070077 LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2]
78 << " returned failure: " << WEXITSTATUS(status);
Paul Crowleyc4547882018-05-16 13:41:01 -070079 return;
80 }
81}
82
Paul Lawrence4818b732016-05-23 22:03:40 +000083static void policy_to_hex(const char* policy, char* hex) {
Eric Biggersb46c3592018-10-23 13:39:07 -070084 for (size_t i = 0, j = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++) {
Paul Lawrence4818b732016-05-23 22:03:40 +000085 hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4];
86 hex[j++] = HEX_LOOKUP[policy[i] & 0x0F];
87 }
Eric Biggersb46c3592018-10-23 13:39:07 -070088 hex[FS_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0';
Paul Lawrence4818b732016-05-23 22:03:40 +000089}
90
91static 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
Eric Biggersb46c3592018-10-23 13:39:07 -0700121static uint8_t fscrypt_get_policy_flags(int filenames_encryption_mode) {
122 if (filenames_encryption_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
Paul Crowley6a0fa622018-03-30 09:42:04 -0700123 // Use legacy padding with our original filenames encryption mode.
Eric Biggersb46c3592018-10-23 13:39:07 -0700124 return FS_POLICY_FLAGS_PAD_4;
Greg Kaiserb46c11c2018-12-03 12:36:56 -0800125 } 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);
Eric Biggersa9fa6052017-02-02 14:37:05 -0800130 }
Paul Crowley6a0fa622018-03-30 09:42:04 -0700131 // 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.
Eric Biggersb46c3592018-10-23 13:39:07 -0700135 return FS_POLICY_FLAGS_PAD_16;
Eric Biggersa9fa6052017-02-02 14:37:05 -0800136}
137
Eric Biggersb46c3592018-10-23 13:39:07 -0700138static bool fscrypt_policy_set(const char *directory, const char *policy,
Eric Biggersa9fa6052017-02-02 14:37:05 -0800139 size_t policy_length,
140 int contents_encryption_mode,
141 int filenames_encryption_mode) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700142 if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
Paul Lawrence4818b732016-05-23 22:03:40 +0000143 LOG(ERROR) << "Policy wrong length: " << policy_length;
144 return false;
145 }
Eric Biggersb46c3592018-10-23 13:39:07 -0700146 char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
Paul Crowley736e2062017-10-10 10:22:46 -0700147 policy_to_hex(policy, policy_hex);
148
Paul Lawrence4818b732016-05-23 22:03:40 +0000149 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
Eric Biggersb46c3592018-10-23 13:39:07 -0700155 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)) {
Paul Crowley736e2062017-10-10 10:22:46 -0700162 PLOG(ERROR) << "Failed to set encryption policy for " << directory << " to " << policy_hex
163 << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode;
Paul Lawrence4818b732016-05-23 22:03:40 +0000164 close(fd);
165 return false;
166 }
167 close(fd);
168
Paul Crowley736e2062017-10-10 10:22:46 -0700169 LOG(INFO) << "Policy for " << directory << " set to " << policy_hex
170 << " modes " << contents_encryption_mode << "/" << filenames_encryption_mode;
Paul Lawrence4818b732016-05-23 22:03:40 +0000171 return true;
172}
173
Eric Biggersb46c3592018-10-23 13:39:07 -0700174static bool fscrypt_policy_get(const char *directory, char *policy,
Eric Biggersa9fa6052017-02-02 14:37:05 -0800175 size_t policy_length,
176 int contents_encryption_mode,
177 int filenames_encryption_mode) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700178 if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
Paul Lawrence4818b732016-05-23 22:03:40 +0000179 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
Eric Biggersb46c3592018-10-23 13:39:07 -0700189 fscrypt_policy fp;
190 memset(&fp, 0, sizeof(fscrypt_policy));
191 if (ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &fp) != 0) {
Paul Lawrence4818b732016-05-23 22:03:40 +0000192 PLOG(ERROR) << "Failed to get encryption policy for " << directory;
193 close(fd);
Paul Crowleye1f6ad42018-05-22 15:58:38 -0700194 log_ls(directory);
Ethan Yonker30b93dd2016-12-06 22:42:14 -0600195 return false;
Paul Lawrence4818b732016-05-23 22:03:40 +0000196 }
197 close(fd);
198
Eric Biggersb46c3592018-10-23 13:39:07 -0700199 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))) {
Paul Lawrence4818b732016-05-23 22:03:40 +0000204 LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
205 return false;
206 }
Eric Biggersb46c3592018-10-23 13:39:07 -0700207 memcpy(policy, fp.master_key_descriptor, FS_KEY_DESCRIPTOR_SIZE);
Paul Lawrence4818b732016-05-23 22:03:40 +0000208
209 return true;
210}
211
Eric Biggersb46c3592018-10-23 13:39:07 -0700212static bool fscrypt_policy_check(const char *directory, const char *policy,
Eric Biggersa9fa6052017-02-02 14:37:05 -0800213 size_t policy_length,
214 int contents_encryption_mode,
215 int filenames_encryption_mode) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700216 if (policy_length != FS_KEY_DESCRIPTOR_SIZE) {
Paul Lawrence4818b732016-05-23 22:03:40 +0000217 LOG(ERROR) << "Policy wrong length: " << policy_length;
218 return false;
219 }
Eric Biggersb46c3592018-10-23 13:39:07 -0700220 char existing_policy[FS_KEY_DESCRIPTOR_SIZE];
221 if (!fscrypt_policy_get(directory, existing_policy, FS_KEY_DESCRIPTOR_SIZE,
Eric Biggersa9fa6052017-02-02 14:37:05 -0800222 contents_encryption_mode,
223 filenames_encryption_mode)) return false;
Eric Biggersb46c3592018-10-23 13:39:07 -0700224 char existing_policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
Paul Lawrence4818b732016-05-23 22:03:40 +0000225
226 policy_to_hex(existing_policy, existing_policy_hex);
227
Eric Biggersb46c3592018-10-23 13:39:07 -0700228 if (memcmp(policy, existing_policy, FS_KEY_DESCRIPTOR_SIZE) != 0) {
229 char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
Paul Lawrence4818b732016-05-23 22:03:40 +0000230 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;
Paul Crowleye1f6ad42018-05-22 15:58:38 -0700233 log_ls(directory);
Paul Lawrence4818b732016-05-23 22:03:40 +0000234 return false;
235 }
236 LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory
237 << " which matches expected value";
238 return true;
239}
240
Eric Biggersb46c3592018-10-23 13:39:07 -0700241int fscrypt_policy_ensure(const char *directory, const char *policy,
Eric Biggersa9fa6052017-02-02 14:37:05 -0800242 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")) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700250 contents_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
Greg Kaiserb46c11c2018-12-03 12:36:56 -0800251 } else if (!strcmp(contents_encryption_mode, "adiantum")) {
252 contents_mode = FS_ENCRYPTION_MODE_ADIANTUM;
Paul Lawrencec096c9c2016-05-24 04:57:23 -0700253 } else if (!strcmp(contents_encryption_mode, "ice")) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700254 contents_mode = FS_ENCRYPTION_MODE_PRIVATE;
Paul Lawrencec096c9c2016-05-24 04:57:23 -0700255 } else {
Eric Biggersa9fa6052017-02-02 14:37:05 -0800256 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")) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700262 filenames_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
Eric Biggersa9fa6052017-02-02 14:37:05 -0800263 } else if (!strcmp(filenames_encryption_mode, "aes-256-heh")) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700264 filenames_mode = FS_ENCRYPTION_MODE_AES_256_HEH;
Greg Kaiserb46c11c2018-12-03 12:36:56 -0800265 } else if (!strcmp(filenames_encryption_mode, "adiantum")) {
266 filenames_mode = FS_ENCRYPTION_MODE_ADIANTUM;
Eric Biggersa9fa6052017-02-02 14:37:05 -0800267 } else {
268 LOG(ERROR) << "Invalid file names encryption mode: "
269 << filenames_encryption_mode;
Paul Lawrencec096c9c2016-05-24 04:57:23 -0700270 return -1;
271 }
272
Paul Lawrence4818b732016-05-23 22:03:40 +0000273 bool is_empty;
274 if (!is_dir_empty(directory, &is_empty)) return -1;
275 if (is_empty) {
Eric Biggersb46c3592018-10-23 13:39:07 -0700276 if (!fscrypt_policy_set(directory, policy, policy_length,
Eric Biggersa9fa6052017-02-02 14:37:05 -0800277 contents_mode, filenames_mode)) return -1;
Paul Lawrence4818b732016-05-23 22:03:40 +0000278 } else {
Eric Biggersb46c3592018-10-23 13:39:07 -0700279 if (!fscrypt_policy_check(directory, policy, policy_length,
Eric Biggersa9fa6052017-02-02 14:37:05 -0800280 contents_mode, filenames_mode)) return -1;
Paul Lawrence4818b732016-05-23 22:03:40 +0000281 }
282 return 0;
283}