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