Paul Lawrence | 377cd19 | 2015-04-28 22:13:04 +0000 | [diff] [blame] | 1 | /* |
Paul Crowley | 8d53b96 | 2016-04-27 10:24:40 -0700 | [diff] [blame] | 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. |
Paul Lawrence | 377cd19 | 2015-04-28 22:13:04 +0000 | [diff] [blame] | 15 | */ |
| 16 | |
Eric Biggers | b46c359 | 2018-10-23 13:39:07 -0700 | [diff] [blame] | 17 | #include "fscrypt/fscrypt.h" |
Paul Lawrence | 92da49d | 2015-02-25 15:11:13 -0800 | [diff] [blame] | 18 | |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 19 | #include <android-base/file.h> |
| 20 | #include <android-base/logging.h> |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 21 | #include <android-base/properties.h> |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 22 | #include <android-base/strings.h> |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 23 | #include <android-base/unique_fd.h> |
Tao Bao | 06ca811 | 2016-10-05 12:44:18 -0700 | [diff] [blame] | 24 | #include <asm/ioctl.h> |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 25 | #include <cutils/properties.h> |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 26 | #include <errno.h> |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 27 | #include <fcntl.h> |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 28 | #include <linux/fscrypt.h> |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 29 | #include <logwrap/logwrap.h> |
Tao Bao | 06ca811 | 2016-10-05 12:44:18 -0700 | [diff] [blame] | 30 | #include <string.h> |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 31 | #include <sys/stat.h> |
| 32 | #include <sys/types.h> |
Tao Bao | 06ca811 | 2016-10-05 12:44:18 -0700 | [diff] [blame] | 33 | #include <unistd.h> |
Paul Crowley | c454788 | 2018-05-16 13:41:01 -0700 | [diff] [blame] | 34 | #include <utils/misc.h> |
Paul Lawrence | 92da49d | 2015-02-25 15:11:13 -0800 | [diff] [blame] | 35 | |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 36 | #include <array> |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 37 | #include <string> |
| 38 | #include <vector> |
| 39 | |
| 40 | using namespace std::string_literals; |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 41 | |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 42 | /* modes not supported by upstream kernel, so not in <linux/fscrypt.h> */ |
| 43 | #define FSCRYPT_MODE_AES_256_HEH 126 |
| 44 | #define FSCRYPT_MODE_PRIVATE 127 |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 45 | |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 46 | #define HEX_LOOKUP "0123456789abcdef" |
| 47 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 48 | struct ModeLookupEntry { |
| 49 | std::string name; |
| 50 | int id; |
| 51 | }; |
| 52 | |
| 53 | static const auto contents_modes = std::vector<ModeLookupEntry>{ |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 54 | {"aes-256-xts"s, FSCRYPT_MODE_AES_256_XTS}, |
| 55 | {"software"s, FSCRYPT_MODE_AES_256_XTS}, |
| 56 | {"adiantum"s, FSCRYPT_MODE_ADIANTUM}, |
| 57 | {"ice"s, FSCRYPT_MODE_PRIVATE}, |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 58 | }; |
| 59 | |
| 60 | static const auto filenames_modes = std::vector<ModeLookupEntry>{ |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 61 | {"aes-256-cts"s, FSCRYPT_MODE_AES_256_CTS}, |
| 62 | {"aes-256-heh"s, FSCRYPT_MODE_AES_256_HEH}, |
| 63 | {"adiantum"s, FSCRYPT_MODE_ADIANTUM}, |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 64 | }; |
| 65 | |
| 66 | static bool LookupModeByName(const std::vector<struct ModeLookupEntry>& modes, |
| 67 | const std::string& name, int* result) { |
| 68 | for (const auto& e : modes) { |
| 69 | if (e.name == name) { |
| 70 | *result = e.id; |
| 71 | return true; |
| 72 | } |
| 73 | } |
| 74 | return false; |
| 75 | } |
| 76 | |
| 77 | static bool LookupModeById(const std::vector<struct ModeLookupEntry>& modes, int id, |
| 78 | std::string* result) { |
| 79 | for (const auto& e : modes) { |
| 80 | if (e.id == id) { |
| 81 | *result = e.name; |
| 82 | return true; |
| 83 | } |
| 84 | } |
| 85 | return false; |
| 86 | } |
| 87 | |
Eric Biggers | b46c359 | 2018-10-23 13:39:07 -0700 | [diff] [blame] | 88 | bool fscrypt_is_native() { |
Paul Crowley | 8d53b96 | 2016-04-27 10:24:40 -0700 | [diff] [blame] | 89 | char value[PROPERTY_VALUE_MAX]; |
| 90 | property_get("ro.crypto.type", value, "none"); |
| 91 | return !strcmp(value, "file"); |
| 92 | } |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 93 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 94 | namespace android { |
| 95 | namespace fscrypt { |
| 96 | |
Paul Crowley | e1f6ad4 | 2018-05-22 15:58:38 -0700 | [diff] [blame] | 97 | static void log_ls(const char* dirname) { |
| 98 | std::array<const char*, 3> argv = {"ls", "-laZ", dirname}; |
Paul Crowley | c454788 | 2018-05-16 13:41:01 -0700 | [diff] [blame] | 99 | int status = 0; |
| 100 | auto res = |
ThiƩbaud Weksteen | c54df90 | 2020-10-26 15:33:21 +0100 | [diff] [blame] | 101 | logwrap_fork_execvp(argv.size(), argv.data(), &status, false, LOG_ALOG, false, nullptr); |
Paul Crowley | c454788 | 2018-05-16 13:41:01 -0700 | [diff] [blame] | 102 | if (res != 0) { |
Paul Crowley | e1f6ad4 | 2018-05-22 15:58:38 -0700 | [diff] [blame] | 103 | PLOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] << "failed"; |
Paul Crowley | c454788 | 2018-05-16 13:41:01 -0700 | [diff] [blame] | 104 | return; |
| 105 | } |
| 106 | if (!WIFEXITED(status)) { |
Paul Crowley | e1f6ad4 | 2018-05-22 15:58:38 -0700 | [diff] [blame] | 107 | LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] |
| 108 | << " did not exit normally, status: " << status; |
Paul Crowley | c454788 | 2018-05-16 13:41:01 -0700 | [diff] [blame] | 109 | return; |
| 110 | } |
| 111 | if (WEXITSTATUS(status) != 0) { |
Paul Crowley | e1f6ad4 | 2018-05-22 15:58:38 -0700 | [diff] [blame] | 112 | LOG(ERROR) << argv[0] << " " << argv[1] << " " << argv[2] |
| 113 | << " returned failure: " << WEXITSTATUS(status); |
Paul Crowley | c454788 | 2018-05-16 13:41:01 -0700 | [diff] [blame] | 114 | return; |
| 115 | } |
| 116 | } |
| 117 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 118 | void BytesToHex(const std::string& bytes, std::string* hex) { |
| 119 | hex->clear(); |
| 120 | for (char c : bytes) { |
| 121 | *hex += HEX_LOOKUP[(c & 0xF0) >> 4]; |
| 122 | *hex += HEX_LOOKUP[c & 0x0F]; |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 123 | } |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 124 | } |
| 125 | |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 126 | static bool fscrypt_is_encrypted(int fd) { |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 127 | fscrypt_policy_v1 policy; |
| 128 | |
| 129 | // success => encrypted with v1 policy |
| 130 | // EINVAL => encrypted with v2 policy |
| 131 | // ENODATA => not encrypted |
| 132 | return ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) == 0 || errno == EINVAL; |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 133 | } |
| 134 | |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 135 | unsigned int GetFirstApiLevel() { |
| 136 | return android::base::GetUintProperty<unsigned int>("ro.product.first_api_level", 0); |
| 137 | } |
| 138 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 139 | bool OptionsToString(const EncryptionOptions& options, std::string* options_string) { |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 140 | return OptionsToStringForApiLevel(GetFirstApiLevel(), options, options_string); |
| 141 | } |
| 142 | |
| 143 | bool OptionsToStringForApiLevel(unsigned int first_api_level, const EncryptionOptions& options, |
| 144 | std::string* options_string) { |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 145 | std::string contents_mode, filenames_mode; |
| 146 | if (!LookupModeById(contents_modes, options.contents_mode, &contents_mode)) { |
| 147 | return false; |
| 148 | } |
| 149 | if (!LookupModeById(filenames_modes, options.filenames_mode, &filenames_mode)) { |
| 150 | return false; |
| 151 | } |
| 152 | *options_string = contents_mode + ":" + filenames_mode + ":v" + std::to_string(options.version); |
Paul Crowley | 3c78d41 | 2019-10-25 17:09:03 -0700 | [diff] [blame] | 153 | if ((options.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64)) { |
| 154 | *options_string += "+inlinecrypt_optimized"; |
| 155 | } |
Paul Crowley | 476ce0a | 2020-05-20 16:05:41 -0700 | [diff] [blame] | 156 | if ((options.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) { |
| 157 | *options_string += "+emmc_optimized"; |
| 158 | } |
Barani Muthukumaran | 3560267 | 2020-01-23 17:40:01 -0800 | [diff] [blame] | 159 | if (options.use_hw_wrapped_key) { |
| 160 | *options_string += "+wrappedkey_v0"; |
| 161 | } |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 162 | |
Paul Crowley | 5e2fbc4 | 2019-10-24 23:27:50 -0700 | [diff] [blame] | 163 | EncryptionOptions options_check; |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 164 | if (!ParseOptionsForApiLevel(first_api_level, *options_string, &options_check)) { |
Paul Crowley | 5e2fbc4 | 2019-10-24 23:27:50 -0700 | [diff] [blame] | 165 | LOG(ERROR) << "Internal error serializing options as string: " << *options_string; |
| 166 | return false; |
| 167 | } |
Barani Muthukumaran | 3560267 | 2020-01-23 17:40:01 -0800 | [diff] [blame] | 168 | if (options != options_check) { |
Paul Crowley | 5e2fbc4 | 2019-10-24 23:27:50 -0700 | [diff] [blame] | 169 | LOG(ERROR) << "Internal error serializing options as string, round trip failed: " |
| 170 | << *options_string; |
| 171 | return false; |
| 172 | } |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 173 | return true; |
| 174 | } |
Eric Biggers | a9fa605 | 2017-02-02 14:37:05 -0800 | [diff] [blame] | 175 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 176 | bool ParseOptions(const std::string& options_string, EncryptionOptions* options) { |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 177 | return ParseOptionsForApiLevel(GetFirstApiLevel(), options_string, options); |
| 178 | } |
| 179 | |
| 180 | bool ParseOptionsForApiLevel(unsigned int first_api_level, const std::string& options_string, |
| 181 | EncryptionOptions* options) { |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 182 | auto parts = android::base::Split(options_string, ":"); |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 183 | if (parts.size() > 3) { |
| 184 | LOG(ERROR) << "Invalid encryption options: " << options; |
Paul Crowley | 5e2fbc4 | 2019-10-24 23:27:50 -0700 | [diff] [blame] | 185 | return false; |
| 186 | } |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 187 | options->contents_mode = FSCRYPT_MODE_AES_256_XTS; |
| 188 | if (parts.size() > 0 && !parts[0].empty()) { |
| 189 | if (!LookupModeByName(contents_modes, parts[0], &options->contents_mode)) { |
| 190 | LOG(ERROR) << "Invalid file contents encryption mode: " << parts[0]; |
Paul Crowley | be2aeea | 2019-10-25 10:19:10 -0700 | [diff] [blame] | 191 | return false; |
Paul Crowley | 5e2fbc4 | 2019-10-24 23:27:50 -0700 | [diff] [blame] | 192 | } |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 193 | } |
| 194 | if (options->contents_mode == FSCRYPT_MODE_ADIANTUM) { |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 195 | options->filenames_mode = FSCRYPT_MODE_ADIANTUM; |
Paul Lawrence | c096c9c | 2016-05-24 04:57:23 -0700 | [diff] [blame] | 196 | } else { |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 197 | options->filenames_mode = FSCRYPT_MODE_AES_256_CTS; |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 198 | } |
ThiƩbaud Weksteen | c54df90 | 2020-10-26 15:33:21 +0100 | [diff] [blame] | 199 | if (parts.size() > 1 && !parts[1].empty()) { |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 200 | if (!LookupModeByName(filenames_modes, parts[1], &options->filenames_mode)) { |
| 201 | LOG(ERROR) << "Invalid file names encryption mode: " << parts[1]; |
| 202 | return false; |
| 203 | } |
| 204 | } |
| 205 | // Default to v2 after Q |
Eric Biggers | 1cb5629 | 2020-08-10 11:19:06 -0700 | [diff] [blame] | 206 | options->version = first_api_level > __ANDROID_API_Q__ ? 2 : 1; |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 207 | options->flags = 0; |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 208 | options->use_hw_wrapped_key = false; |
| 209 | if (parts.size() > 2 && !parts[2].empty()) { |
Paul Crowley | 3c78d41 | 2019-10-25 17:09:03 -0700 | [diff] [blame] | 210 | auto flags = android::base::Split(parts[2], "+"); |
| 211 | for (const auto& flag : flags) { |
| 212 | if (flag == "v1") { |
| 213 | options->version = 1; |
| 214 | } else if (flag == "v2") { |
| 215 | options->version = 2; |
| 216 | } else if (flag == "inlinecrypt_optimized") { |
| 217 | options->flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64; |
Paul Crowley | 476ce0a | 2020-05-20 16:05:41 -0700 | [diff] [blame] | 218 | } else if (flag == "emmc_optimized") { |
| 219 | options->flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32; |
Barani Muthukumaran | 3560267 | 2020-01-23 17:40:01 -0800 | [diff] [blame] | 220 | } else if (flag == "wrappedkey_v0") { |
| 221 | options->use_hw_wrapped_key = true; |
Paul Crowley | 3c78d41 | 2019-10-25 17:09:03 -0700 | [diff] [blame] | 222 | } else { |
| 223 | LOG(ERROR) << "Unknown flag: " << flag; |
| 224 | return false; |
| 225 | } |
| 226 | } |
| 227 | } |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 228 | |
| 229 | // In the original setting of v1 policies and AES-256-CTS we used 4-byte |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 230 | // padding of filenames, so retain that on old first_api_levels. |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 231 | // |
| 232 | // For everything else, use 16-byte padding. This is more secure (it helps |
| 233 | // hide the length of filenames), and it makes the inputs evenly divisible |
| 234 | // into cipher blocks which is more efficient for encryption and decryption. |
Eric Biggers | 1cb5629 | 2020-08-10 11:19:06 -0700 | [diff] [blame] | 235 | if (first_api_level <= __ANDROID_API_Q__ && options->version == 1 && |
| 236 | options->filenames_mode == FSCRYPT_MODE_AES_256_CTS) { |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 237 | options->flags |= FSCRYPT_POLICY_FLAGS_PAD_4; |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 238 | } else { |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 239 | options->flags |= FSCRYPT_POLICY_FLAGS_PAD_16; |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | // Use DIRECT_KEY for Adiantum, since it's much more efficient but just as |
| 243 | // secure since Android doesn't reuse the same master key for multiple |
| 244 | // encryption modes. |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 245 | if (options->contents_mode == FSCRYPT_MODE_ADIANTUM) { |
| 246 | if (options->filenames_mode != FSCRYPT_MODE_ADIANTUM) { |
ThiƩbaud Weksteen | c54df90 | 2020-10-26 15:33:21 +0100 | [diff] [blame] | 247 | LOG(ERROR) << "Adiantum must be both contents and filenames mode or neither, invalid " |
| 248 | "options: " |
| 249 | << options_string; |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 250 | return false; |
| 251 | } |
Eric Biggers | 9b14aa3 | 2019-12-16 16:02:23 -0800 | [diff] [blame] | 252 | options->flags |= FSCRYPT_POLICY_FLAG_DIRECT_KEY; |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 253 | } else if (options->filenames_mode == FSCRYPT_MODE_ADIANTUM) { |
ThiƩbaud Weksteen | c54df90 | 2020-10-26 15:33:21 +0100 | [diff] [blame] | 254 | LOG(ERROR) |
| 255 | << "Adiantum must be both contents and filenames mode or neither, invalid options: " |
| 256 | << options_string; |
Paul Crowley | 47212f0 | 2020-02-18 21:30:03 -0800 | [diff] [blame] | 257 | return false; |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 258 | } |
Paul Crowley | 476ce0a | 2020-05-20 16:05:41 -0700 | [diff] [blame] | 259 | |
| 260 | // IV generation methods are mutually exclusive |
| 261 | int iv_methods = 0; |
| 262 | iv_methods += !!(options->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64); |
| 263 | iv_methods += !!(options->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32); |
| 264 | iv_methods += !!(options->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY); |
| 265 | if (iv_methods > 1) { |
| 266 | LOG(ERROR) << "At most one IV generation method can be set, invalid options: " |
| 267 | << options_string; |
| 268 | return false; |
| 269 | } |
| 270 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 271 | return true; |
| 272 | } |
Paul Lawrence | c096c9c | 2016-05-24 04:57:23 -0700 | [diff] [blame] | 273 | |
Paul Crowley | 9444d62 | 2019-10-24 22:51:20 -0700 | [diff] [blame] | 274 | static std::string PolicyDebugString(const EncryptionPolicy& policy) { |
| 275 | std::stringstream ss; |
| 276 | std::string ref_hex; |
| 277 | BytesToHex(policy.key_raw_ref, &ref_hex); |
| 278 | ss << ref_hex; |
| 279 | ss << " v" << policy.options.version; |
| 280 | ss << " modes " << policy.options.contents_mode << "/" << policy.options.filenames_mode; |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 281 | ss << std::hex << " flags 0x" << policy.options.flags; |
Paul Crowley | 9444d62 | 2019-10-24 22:51:20 -0700 | [diff] [blame] | 282 | return ss.str(); |
| 283 | } |
| 284 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 285 | bool EnsurePolicy(const EncryptionPolicy& policy, const std::string& directory) { |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 286 | union { |
| 287 | fscrypt_policy_v1 v1; |
| 288 | fscrypt_policy_v2 v2; |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 289 | } kern_policy; |
| 290 | memset(&kern_policy, 0, sizeof(kern_policy)); |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 291 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 292 | switch (policy.options.version) { |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 293 | case 1: |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 294 | if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) { |
| 295 | LOG(ERROR) << "Invalid key descriptor length for v1 policy: " |
| 296 | << policy.key_raw_ref.size(); |
| 297 | return false; |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 298 | } |
| 299 | // Careful: FSCRYPT_POLICY_V1 is actually 0 in the API, so make sure |
| 300 | // to use it here instead of a literal 1. |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 301 | kern_policy.v1.version = FSCRYPT_POLICY_V1; |
| 302 | kern_policy.v1.contents_encryption_mode = policy.options.contents_mode; |
| 303 | kern_policy.v1.filenames_encryption_mode = policy.options.filenames_mode; |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 304 | kern_policy.v1.flags = policy.options.flags; |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 305 | policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v1.master_key_descriptor), |
| 306 | FSCRYPT_KEY_DESCRIPTOR_SIZE); |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 307 | break; |
| 308 | case 2: |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 309 | if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) { |
| 310 | LOG(ERROR) << "Invalid key identifier length for v2 policy: " |
| 311 | << policy.key_raw_ref.size(); |
| 312 | return false; |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 313 | } |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 314 | kern_policy.v2.version = FSCRYPT_POLICY_V2; |
| 315 | kern_policy.v2.contents_encryption_mode = policy.options.contents_mode; |
| 316 | kern_policy.v2.filenames_encryption_mode = policy.options.filenames_mode; |
Paul Crowley | 22eb1d4 | 2019-10-25 10:28:53 -0700 | [diff] [blame] | 317 | kern_policy.v2.flags = policy.options.flags; |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 318 | policy.key_raw_ref.copy(reinterpret_cast<char*>(kern_policy.v2.master_key_identifier), |
| 319 | FSCRYPT_KEY_IDENTIFIER_SIZE); |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 320 | break; |
| 321 | default: |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 322 | LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version; |
| 323 | return false; |
Eric Biggers | 17115c7 | 2019-09-13 11:07:42 -0700 | [diff] [blame] | 324 | } |
| 325 | |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 326 | android::base::unique_fd fd(open(directory.c_str(), O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC)); |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 327 | if (fd == -1) { |
| 328 | PLOG(ERROR) << "Failed to open directory " << directory; |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 329 | return false; |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 330 | } |
| 331 | |
| 332 | bool already_encrypted = fscrypt_is_encrypted(fd); |
| 333 | |
| 334 | // FS_IOC_SET_ENCRYPTION_POLICY will set the policy if the directory is |
| 335 | // unencrypted; otherwise it will verify that the existing policy matches. |
| 336 | // Setting the policy will fail if the directory is already nonempty. |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 337 | if (ioctl(fd, FS_IOC_SET_ENCRYPTION_POLICY, &kern_policy) != 0) { |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 338 | std::string reason; |
| 339 | switch (errno) { |
| 340 | case EEXIST: |
| 341 | reason = "The directory already has a different encryption policy."; |
| 342 | break; |
| 343 | default: |
| 344 | reason = strerror(errno); |
| 345 | break; |
| 346 | } |
Paul Crowley | 9444d62 | 2019-10-24 22:51:20 -0700 | [diff] [blame] | 347 | LOG(ERROR) << "Failed to set encryption policy of " << directory << " to " |
| 348 | << PolicyDebugString(policy) << ": " << reason; |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 349 | if (errno == ENOTEMPTY) { |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 350 | log_ls(directory.c_str()); |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 351 | } |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 352 | return false; |
Eric Biggers | b901508 | 2019-09-05 12:18:30 -0700 | [diff] [blame] | 353 | } |
| 354 | |
| 355 | if (already_encrypted) { |
Paul Crowley | 9444d62 | 2019-10-24 22:51:20 -0700 | [diff] [blame] | 356 | LOG(INFO) << "Verified that " << directory << " has the encryption policy " |
| 357 | << PolicyDebugString(policy); |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 358 | } else { |
Paul Crowley | 9444d62 | 2019-10-24 22:51:20 -0700 | [diff] [blame] | 359 | LOG(INFO) << "Encryption policy of " << directory << " set to " |
| 360 | << PolicyDebugString(policy); |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 361 | } |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 362 | return true; |
Paul Lawrence | 4818b73 | 2016-05-23 22:03:40 +0000 | [diff] [blame] | 363 | } |
Paul Crowley | f6ca2c3 | 2019-10-24 14:51:44 -0700 | [diff] [blame] | 364 | |
| 365 | } // namespace fscrypt |
| 366 | } // namespace android |