1 /* 2 * Copyright (C) 2016 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 "KeyBuffer.h" 18 #include "MetadataCrypt.h" 19 20 #include <string> 21 #include <thread> 22 #include <vector> 23 #include <algorithm> 24 25 #include <fcntl.h> 26 #include <sys/ioctl.h> 27 #include <sys/param.h> 28 #include <sys/stat.h> 29 #include <sys/types.h> 30 31 #include <linux/dm-ioctl.h> 32 33 #include <android-base/logging.h> 34 #include <android-base/unique_fd.h> 35 #include <cutils/properties.h> 36 #include <fs_mgr.h> 37 38 #include "EncryptInplace.h" 39 #include "KeyStorage.h" 40 #include "KeyUtil.h" 41 #include "secontext.h" 42 #include "Utils.h" 43 #include "VoldUtil.h" 44 45 extern struct fstab *fstab; 46 #define DM_CRYPT_BUF_SIZE 4096 47 #define TABLE_LOAD_RETRIES 10 48 #define DEFAULT_KEY_TARGET_TYPE "default-key" 49 50 using android::vold::KeyBuffer; 51 52 static const std::string kDmNameUserdata = "userdata"; 53 54 static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) { 55 // fs_mgr_do_mount runs fsck. Use setexeccon to run trusted 56 // partitions in the fsck domain. 57 if (setexeccon(secontextFsck())) { 58 PLOG(ERROR) << "Failed to setexeccon"; 59 return false; 60 } 61 auto mount_rc = fs_mgr_do_mount(fstab, const_cast<char*>(mount_point), 62 const_cast<char*>(blk_device), nullptr); 63 if (setexeccon(nullptr)) { 64 PLOG(ERROR) << "Failed to clear setexeccon"; 65 return false; 66 } 67 if (mount_rc != 0) { 68 LOG(ERROR) << "fs_mgr_do_mount failed with rc " << mount_rc; 69 return false; 70 } 71 LOG(DEBUG) << "Mounted " << mount_point; 72 return true; 73 } 74 75 static bool read_key(bool create_if_absent, KeyBuffer* key) { 76 auto data_rec = fs_mgr_get_crypt_entry(fstab); 77 if (!data_rec) { 78 LOG(ERROR) << "Failed to get data_rec"; 79 return false; 80 } 81 if (!data_rec->key_dir) { 82 LOG(ERROR) << "Failed to get key_dir"; 83 return false; 84 } 85 LOG(DEBUG) << "key_dir: " << data_rec->key_dir; 86 if (!android::vold::pathExists(data_rec->key_dir)) { 87 if (mkdir(data_rec->key_dir, 0777) != 0) { 88 PLOG(ERROR) << "Unable to create: " << data_rec->key_dir; 89 return false; 90 } 91 LOG(DEBUG) << "Created: " << data_rec->key_dir; 92 } 93 std::string key_dir = data_rec->key_dir; 94 auto dir = key_dir + "/key"; 95 auto temp = key_dir + "/tmp"; 96 if (!android::vold::retrieveKey(create_if_absent, dir, temp, key)) return false; 97 return true; 98 } 99 100 static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuffer& key) { 101 KeyBuffer hex_key; 102 if (android::vold::StrToHex(key, hex_key) != android::OK) { 103 LOG(ERROR) << "Failed to turn key to hex"; 104 return KeyBuffer(); 105 } 106 auto res = KeyBuffer() + "AES-256-XTS " + hex_key + " " + real_blkdev.c_str() + " 0"; 107 LOG(DEBUG) << "crypt_params: " << std::string(res.data(), res.size()); 108 return res; 109 } 110 111 static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t *nr_sec) { 112 android::base::unique_fd dev_fd(TEMP_FAILURE_RETRY(open( 113 real_blkdev.c_str(), O_RDONLY | O_CLOEXEC, 0))); 114 if (dev_fd == -1) { 115 PLOG(ERROR) << "Unable to open " << real_blkdev << " to measure size"; 116 return false; 117 } 118 unsigned long res; 119 // TODO: should use BLKGETSIZE64 120 get_blkdev_size(dev_fd.get(), &res); 121 if (res == 0) { 122 PLOG(ERROR) << "Unable to measure size of " << real_blkdev; 123 return false; 124 } 125 *nr_sec = res; 126 return true; 127 } 128 129 static struct dm_ioctl* dm_ioctl_init(char *buffer, size_t buffer_size, 130 const std::string& dm_name) { 131 if (buffer_size < sizeof(dm_ioctl)) { 132 LOG(ERROR) << "dm_ioctl buffer too small"; 133 return nullptr; 134 } 135 136 memset(buffer, 0, buffer_size); 137 struct dm_ioctl* io = (struct dm_ioctl*) buffer; 138 io->data_size = buffer_size; 139 io->data_start = sizeof(struct dm_ioctl); 140 io->version[0] = 4; 141 io->version[1] = 0; 142 io->version[2] = 0; 143 io->flags = 0; 144 dm_name.copy(io->name, sizeof(io->name)); 145 return io; 146 } 147 148 static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec, 149 const std::string& target_type, const KeyBuffer& crypt_params, 150 std::string* crypto_blkdev) { 151 android::base::unique_fd dm_fd(TEMP_FAILURE_RETRY(open( 152 "/dev/device-mapper", O_RDWR | O_CLOEXEC, 0))); 153 if (dm_fd == -1) { 154 PLOG(ERROR) << "Cannot open device-mapper"; 155 return false; 156 } 157 alignas(struct dm_ioctl) char buffer[DM_CRYPT_BUF_SIZE]; 158 auto io = dm_ioctl_init(buffer, sizeof(buffer), dm_name); 159 if (!io || ioctl(dm_fd.get(), DM_DEV_CREATE, io) != 0) { 160 PLOG(ERROR) << "Cannot create dm-crypt device " << dm_name; 161 return false; 162 } 163 164 // Get the device status, in particular, the name of its device file 165 io = dm_ioctl_init(buffer, sizeof(buffer), dm_name); 166 if (ioctl(dm_fd.get(), DM_DEV_STATUS, io) != 0) { 167 PLOG(ERROR) << "Cannot retrieve dm-crypt device status " << dm_name; 168 return false; 169 } 170 *crypto_blkdev = std::string() + "/dev/block/dm-" + std::to_string( 171 (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00)); 172 173 io = dm_ioctl_init(buffer, sizeof(buffer), dm_name); 174 size_t paramix = io->data_start + sizeof(struct dm_target_spec); 175 size_t nullix = paramix + crypt_params.size(); 176 size_t endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary 177 178 if (endix > sizeof(buffer)) { 179 LOG(ERROR) << "crypt_params too big for DM_CRYPT_BUF_SIZE"; 180 return false; 181 } 182 183 io->target_count = 1; 184 auto tgt = (struct dm_target_spec *) (buffer + io->data_start); 185 tgt->status = 0; 186 tgt->sector_start = 0; 187 tgt->length = nr_sec; 188 target_type.copy(tgt->target_type, sizeof(tgt->target_type)); 189 memcpy(buffer + paramix, crypt_params.data(), 190 std::min(crypt_params.size(), sizeof(buffer) - paramix)); 191 buffer[nullix] = '\0'; 192 tgt->next = endix; 193 194 for (int i = 0; ; i++) { 195 if (ioctl(dm_fd.get(), DM_TABLE_LOAD, io) == 0) { 196 break; 197 } 198 if (i+1 >= TABLE_LOAD_RETRIES) { 199 PLOG(ERROR) << "DM_TABLE_LOAD ioctl failed"; 200 return false; 201 } 202 PLOG(INFO) << "DM_TABLE_LOAD ioctl failed, retrying"; 203 usleep(500000); 204 } 205 206 // Resume this device to activate it 207 io = dm_ioctl_init(buffer, sizeof(buffer), dm_name); 208 if (ioctl(dm_fd.get(), DM_DEV_SUSPEND, io)) { 209 PLOG(ERROR) << "Cannot resume dm-crypt device " << dm_name; 210 return false; 211 } 212 return true; 213 } 214 215 #define DATA_PREP_TIMEOUT 1000 216 static bool prep_data_fs(void) 217 { 218 // NOTE: post_fs_data results in init calling back around to vold, so all 219 // callers to this method must be async 220 221 /* Do the prep of the /data filesystem */ 222 property_set("vold.post_fs_data_done", "0"); 223 property_set("vold.decrypt", "trigger_post_fs_data"); 224 LOG(DEBUG) << "Waiting for post_fs_data_done"; 225 226 /* Wait a max of 50 seconds, hopefully it takes much less */ 227 for (int i = 0; ; i++) { 228 char p[PROPERTY_VALUE_MAX]; 229 230 property_get("vold.post_fs_data_done", p, "0"); 231 if (*p == '1') { 232 LOG(INFO) << "Successful data prep"; 233 return true; 234 } 235 if (i + 1 == DATA_PREP_TIMEOUT) { 236 LOG(ERROR) << "post_fs_data timed out"; 237 return false; 238 } 239 usleep(50000); 240 } 241 } 242 243 static void async_kick_off() { 244 LOG(DEBUG) << "Asynchronously restarting framework"; 245 sleep(2); // TODO: this mirrors cryptfs, but can it be made shorter? 246 property_set("vold.decrypt", "trigger_load_persist_props"); 247 if (!prep_data_fs()) return; 248 /* startup service classes main and late_start */ 249 property_set("vold.decrypt", "trigger_restart_framework"); 250 } 251 252 bool e4crypt_mount_metadata_encrypted() { 253 LOG(DEBUG) << "e4crypt_mount_default_encrypted"; 254 KeyBuffer key; 255 if (!read_key(false, &key)) return false; 256 auto data_rec = fs_mgr_get_crypt_entry(fstab); 257 if (!data_rec) { 258 LOG(ERROR) << "Failed to get data_rec"; 259 return false; 260 } 261 uint64_t nr_sec; 262 if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false; 263 std::string crypto_blkdev; 264 if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, DEFAULT_KEY_TARGET_TYPE, 265 default_key_params(data_rec->blk_device, key), &crypto_blkdev)) return false; 266 // FIXME handle the corrupt case 267 268 LOG(DEBUG) << "Restarting filesystem for metadata encryption"; 269 mount_via_fs_mgr(data_rec->mount_point, crypto_blkdev.c_str()); 270 std::thread(&async_kick_off).detach(); 271 return true; 272 } 273 274 bool e4crypt_enable_crypto() { 275 LOG(DEBUG) << "e4crypt_enable_crypto"; 276 char encrypted_state[PROPERTY_VALUE_MAX]; 277 property_get("ro.crypto.state", encrypted_state, ""); 278 if (strcmp(encrypted_state, "")) { 279 LOG(DEBUG) << "e4crypt_enable_crypto got unexpected starting state: " << encrypted_state; 280 return false; 281 } 282 283 KeyBuffer key_ref; 284 if (!read_key(true, &key_ref)) return false; 285 286 auto data_rec = fs_mgr_get_crypt_entry(fstab); 287 if (!data_rec) { 288 LOG(ERROR) << "Failed to get data_rec"; 289 return false; 290 } 291 uint64_t nr_sec; 292 if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false; 293 294 std::string crypto_blkdev; 295 if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, DEFAULT_KEY_TARGET_TYPE, 296 default_key_params(data_rec->blk_device, key_ref), &crypto_blkdev)) return false; 297 298 LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec; 299 off64_t size_already_done = 0; 300 auto rc = cryptfs_enable_inplace(const_cast<char *>(crypto_blkdev.c_str()), 301 data_rec->blk_device, nr_sec, &size_already_done, nr_sec, 0); 302 if (rc != 0) { 303 LOG(ERROR) << "Inplace crypto failed with code: " << rc; 304 return false; 305 } 306 if (static_cast<uint64_t>(size_already_done) != nr_sec) { 307 LOG(ERROR) << "Inplace crypto only got up to sector: " << size_already_done; 308 return false; 309 } 310 LOG(INFO) << "Inplace encryption complete"; 311 312 property_set("ro.crypto.state", "encrypted"); 313 property_set("ro.crypto.type", "file"); 314 315 mount_via_fs_mgr(data_rec->mount_point, crypto_blkdev.c_str()); 316 property_set("vold.decrypt", "trigger_reset_main"); 317 std::thread(&async_kick_off).detach(); 318 return true; 319 } 320