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 "ext4_crypt.h" 18 19#include <dirent.h> 20#include <errno.h> 21#include <string.h> 22#include <unistd.h> 23 24#include <fcntl.h> 25#include <asm/ioctl.h> 26#include <sys/syscall.h> 27#include <sys/stat.h> 28#include <sys/types.h> 29 30#include <android-base/file.h> 31#include <android-base/logging.h> 32#include <cutils/properties.h> 33 34#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy" 35#define EXT4_KEYREF_DELIMITER ((char)'.') 36 37// ext4enc:TODO Include structure from somewhere sensible 38// MUST be in sync with ext4_crypto.c in kernel 39#define EXT4_KEY_DESCRIPTOR_SIZE 8 40#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17 41 42struct ext4_encryption_policy { 43 char version; 44 char contents_encryption_mode; 45 char filenames_encryption_mode; 46 char flags; 47 char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; 48} __attribute__((__packed__)); 49 50#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 51#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 52#define EXT4_ENCRYPTION_MODE_PRIVATE 127 53 54// ext4enc:TODO Get value from somewhere sensible 55#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy) 56#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) 57 58#define HEX_LOOKUP "0123456789abcdef" 59 60bool e4crypt_is_native() { 61 char value[PROPERTY_VALUE_MAX]; 62 property_get("ro.crypto.type", value, "none"); 63 return !strcmp(value, "file"); 64} 65 66static void policy_to_hex(const char* policy, char* hex) { 67 for (size_t i = 0, j = 0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++) { 68 hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4]; 69 hex[j++] = HEX_LOOKUP[policy[i] & 0x0F]; 70 } 71 hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0'; 72} 73 74static bool is_dir_empty(const char *dirname, bool *is_empty) 75{ 76 int n = 0; 77 auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(dirname), closedir); 78 if (!dirp) { 79 PLOG(ERROR) << "Unable to read directory: " << dirname; 80 return false; 81 } 82 for (;;) { 83 errno = 0; 84 auto entry = readdir(dirp.get()); 85 if (!entry) { 86 if (errno) { 87 PLOG(ERROR) << "Unable to read directory: " << dirname; 88 return false; 89 } 90 break; 91 } 92 if (strcmp(entry->d_name, "lost+found") != 0) { // Skip lost+found 93 ++n; 94 if (n > 2) { 95 *is_empty = false; 96 return true; 97 } 98 } 99 } 100 *is_empty = true; 101 return true; 102} 103 104static bool e4crypt_policy_set(const char *directory, const char *policy, 105 size_t policy_length, int contents_encryption_mode) { 106 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 107 LOG(ERROR) << "Policy wrong length: " << policy_length; 108 return false; 109 } 110 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 111 if (fd == -1) { 112 PLOG(ERROR) << "Failed to open directory " << directory; 113 return false; 114 } 115 116 ext4_encryption_policy eep; 117 eep.version = 0; 118 eep.contents_encryption_mode = contents_encryption_mode; 119 eep.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS; 120 eep.flags = 0; 121 memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE); 122 if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) { 123 PLOG(ERROR) << "Failed to set encryption policy for " << directory; 124 close(fd); 125 return false; 126 } 127 close(fd); 128 129 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 130 policy_to_hex(policy, policy_hex); 131 LOG(INFO) << "Policy for " << directory << " set to " << policy_hex; 132 return true; 133} 134 135static bool e4crypt_policy_get(const char *directory, char *policy, 136 size_t policy_length, int contents_encryption_mode) { 137 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 138 LOG(ERROR) << "Policy wrong length: " << policy_length; 139 return false; 140 } 141 142 int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); 143 if (fd == -1) { 144 PLOG(ERROR) << "Failed to open directory " << directory; 145 return false; 146 } 147 148 ext4_encryption_policy eep; 149 memset(&eep, 0, sizeof(ext4_encryption_policy)); 150 if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep) != 0) { 151 PLOG(ERROR) << "Failed to get encryption policy for " << directory; 152 close(fd); 153 return -1; 154 } 155 close(fd); 156 157 if ((eep.version != 0) 158 || (eep.contents_encryption_mode != contents_encryption_mode) 159 || (eep.filenames_encryption_mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) 160 || (eep.flags != 0)) { 161 LOG(ERROR) << "Failed to find matching encryption policy for " << directory; 162 return false; 163 } 164 memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE); 165 166 return true; 167} 168 169static bool e4crypt_policy_check(const char *directory, const char *policy, 170 size_t policy_length, int contents_encryption_mode) { 171 if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) { 172 LOG(ERROR) << "Policy wrong length: " << policy_length; 173 return false; 174 } 175 char existing_policy[EXT4_KEY_DESCRIPTOR_SIZE]; 176 if (!e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE, 177 contents_encryption_mode)) return false; 178 char existing_policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 179 180 policy_to_hex(existing_policy, existing_policy_hex); 181 182 if (memcmp(policy, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) != 0) { 183 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; 184 policy_to_hex(policy, policy_hex); 185 LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory 186 << " which doesn't match expected value " << policy_hex; 187 return false; 188 } 189 LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory 190 << " which matches expected value"; 191 return true; 192} 193 194int e4crypt_policy_ensure(const char *directory, const char *policy, 195 size_t policy_length, const char* contents_encryption_mode) { 196 int mode = 0; 197 if (!strcmp(contents_encryption_mode, "software")) { 198 mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; 199 } else if (!strcmp(contents_encryption_mode, "ice")) { 200 mode = EXT4_ENCRYPTION_MODE_PRIVATE; 201 } else { 202 LOG(ERROR) << "Invalid encryption mode"; 203 return -1; 204 } 205 206 bool is_empty; 207 if (!is_dir_empty(directory, &is_empty)) return -1; 208 if (is_empty) { 209 if (!e4crypt_policy_set(directory, policy, policy_length, 210 mode)) return -1; 211 } else { 212 if (!e4crypt_policy_check(directory, policy, policy_length, 213 mode)) return -1; 214 } 215 return 0; 216} 217