ext4_crypt_init_extensions.cpp revision 92da49db65ffbe0bff1771ecef87ad49e94a0626
1#include "ext4_crypt.h" 2 3#include <string> 4#include <fstream> 5#include <iomanip> 6#include <sstream> 7 8#include <sys/mount.h> 9 10#include <errno.h> 11#include <sys/stat.h> 12#include <cutils/properties.h> 13#include <cutils/sockets.h> 14 15// ext4enc:TODO Use include paths 16#include "../../core/init/log.h" 17#include "../../core/init/util.h" 18 19#include "ext2fs/ext2_fs.h" 20 21static const std::string unencrypted_path = "/unencrypted"; 22static const std::string keyring = "@s"; 23static const std::string arbitrary_sequence_number = "42"; 24 25static key_serial_t device_keyring = -1; 26 27static std::string vold_command(std::string const& command) 28{ 29 INFO("Running command %s\n", command.c_str()); 30 int sock = socket_local_client("vold", 31 ANDROID_SOCKET_NAMESPACE_RESERVED, 32 SOCK_STREAM); 33 34 if (sock < 0) { 35 INFO("Cannot open vold, failing command\n"); 36 return ""; 37 } 38 39 class CloseSocket 40 { 41 int sock_; 42 public: 43 CloseSocket(int sock) : sock_(sock) {} 44 ~CloseSocket() { close(sock_); } 45 }; 46 47 CloseSocket cs(sock); 48 49 // Use arbitrary sequence number. This should only be used when the 50 // framework is down, so this is (mostly) OK. 51 std::string actual_command = arbitrary_sequence_number + " " + command; 52 if (write(sock, actual_command.c_str(), actual_command.size() + 1) < 0) { 53 ERROR("Cannot write command\n"); 54 return ""; 55 } 56 57 while (1) { 58 struct timeval to; 59 to.tv_sec = 10; 60 to.tv_usec = 0; 61 62 fd_set read_fds; 63 FD_ZERO(&read_fds); 64 FD_SET(sock, &read_fds); 65 66 int rc = select(sock + 1, &read_fds, NULL, NULL, &to); 67 if (rc < 0) { 68 ERROR("Error in select %s\n", strerror(errno)); 69 return ""; 70 } else if (!rc) { 71 ERROR("Timeout\n"); 72 return ""; 73 } else if (FD_ISSET(sock, &read_fds)) { 74 char buffer[4096]; 75 memset(buffer, 0, sizeof(buffer)); 76 rc = read(sock, buffer, sizeof(buffer)); 77 if (rc <= 0) { 78 if (rc == 0) { 79 ERROR("Lost connection to Vold - did it crash?\n"); 80 } else { 81 ERROR("Error reading data (%s)\n", strerror(errno)); 82 } 83 return ""; 84 } 85 86 // We don't truly know that this is the correct result. However, 87 // since this will only be used when the framework is down, 88 // it should be OK unless someone is running vdc at the same time. 89 // Worst case we force a reboot in the very rare synchronization 90 // error 91 return std::string(buffer, rc); 92 } 93 } 94} 95 96int e4crypt_create_device_key(const char* dir) 97{ 98 // Make sure folder exists. Use make_dir to set selinux permissions. 99 INFO("Creating test device key\n"); 100 std::string path = std::string() + dir + unencrypted_path; 101 if (make_dir(path.c_str(), 0700) && errno != EEXIST) { 102 ERROR("Failed to create %s with error %s\n", 103 path.c_str(), strerror(errno)); 104 return -1; 105 } 106 107 // Open key if it exists 108 std::string key_path = path + "/key"; 109 std::ifstream key(key_path.c_str(), std::ifstream::binary); 110 111 if (!key.good()) { 112 // Create new key if it doesn't 113 std::ofstream new_key(key_path.c_str(), std::ofstream::binary); 114 if (!new_key) { 115 ERROR("Failed to open %s\n", key_path.c_str()); 116 return -1; 117 } 118 119 std::ifstream urandom("/dev/urandom", std::ifstream::binary); 120 if (!urandom) { 121 ERROR("Failed to open /dev/urandom\n"); 122 return -1; 123 } 124 125 char key_material[32]; 126 urandom.read(key_material, 32); 127 if (!urandom) { 128 ERROR("Failed to read random bytes\n"); 129 return -1; 130 } 131 132 new_key.write(key_material, 32); 133 if (!new_key) { 134 ERROR("Failed to write key material"); 135 return -1; 136 } 137 } 138 139 remove((std::string(dir) + "/ref").c_str()); 140 return 0; 141} 142 143int e4crypt_install_keyring() 144{ 145 device_keyring = add_key("keyring", 146 "e4crypt", 147 0, 148 0, 149 KEY_SPEC_SESSION_KEYRING); 150 151 if (device_keyring == -1) { 152 ERROR("Failed to create keyring\n"); 153 return -1; 154 } 155 156 INFO("Keyring created wth id %d in process %d\n", device_keyring, getpid()); 157 158 // ext4enc:TODO set correct permissions 159 long result = keyctl_setperm(device_keyring, 0x3f3f3f3f); 160 if (result) { 161 ERROR("KEYCTL_SETPERM failed with error %ld\n", result); 162 return -1; 163 } 164 165 return 0; 166} 167 168int e4crypt_install_key(const char* dir) 169{ 170 std::string path = std::string() + dir + unencrypted_path; 171 172 // Open key if it exists 173 std::string key_path = path + "/key"; 174 std::ifstream key(key_path.c_str(), std::ifstream::binary); 175 if (!key.good()) { 176 ERROR("Failed to open key %s\n", key_path.c_str()); 177 return -1; 178 } 179 180 char keyblob[256]; 181 key.read(keyblob, sizeof(keyblob)); 182 std::streamsize keyblob_size = key.gcount(); 183 if (keyblob_size <= 0) { 184 ERROR("Failed to read key data\n"); 185 return -1; 186 } 187 188 // Get password to decrypt as needed 189 if (e4crypt_non_default_key(dir)) { 190 std::string result = vold_command("cryptfs getpw"); 191 // result is either 192 // 200 0 -1 193 // or 194 // 200 0 {{sensitive}} 0001020304 195 // where 0001020304 is hex encoding of password 196 std::istringstream i(result); 197 std::string bit; 198 i >> bit; 199 if (bit != "200") { 200 ERROR("Expecting 200\n"); 201 return -1; 202 } 203 204 i >> bit; 205 if (bit != arbitrary_sequence_number) { 206 ERROR("Expecting %s\n", arbitrary_sequence_number.c_str()); 207 return -1; 208 } 209 210 i >> bit; 211 if (bit != "{{sensitive}}") { 212 INFO("Not encrypted\n"); 213 return -1; 214 } 215 216 i >> bit; 217 } 218 219 // Add key to keyring 220 // ext4enc:TODO Include structure from somewhere sensible 221 // MUST be in sync with ext4_crypto.c in kernel 222 struct ext4_encryption_key { 223 uint32_t mode; 224 char raw[EXT4_MAX_KEY_SIZE]; 225 uint32_t size; 226 }; 227 228 ext4_encryption_key ext4_key = {0, {0}, 0}; 229 memcpy(ext4_key.raw, keyblob, keyblob_size); 230 ext4_key.size = keyblob_size; 231 232 // ext4enc:TODO Use better reference not 1234567890 233 key_serial_t key_id = add_key("logon", "ext4-key:1234567890", 234 (void*)&ext4_key, sizeof(ext4_key), 235 device_keyring); 236 237 if (key_id == -1) { 238 ERROR("Failed to insert key into keyring with error %s\n", 239 strerror(errno)); 240 return -1; 241 } 242 243 INFO("Added key %d to keyring %d in process %d\n", 244 key_id, device_keyring, getpid()); 245 246 // ext4enc:TODO set correct permissions 247 long result = keyctl_setperm(key_id, 0x3f3f3f3f); 248 if (result) { 249 ERROR("KEYCTL_SETPERM failed with error %ld\n", result); 250 return -1; 251 } 252 253 // Save reference to key so we can set policy later 254 std::ofstream(path + "/ref") << "ext4-key:1234567890"; 255 return 0; 256} 257 258int e4crypt_set_directory_policy(const char* dir) 259{ 260 // Only set policy on first level /data directories 261 // ext4enc:TODO don't hard code /data/ 262 if (!dir || strncmp(dir, "/data/", 6) || strchr(dir + 6, '/')) { 263 return 0; 264 } 265 266 std::ifstream ref_file("/data/unencrypted/ref"); 267 if (!ref_file) { 268 ERROR("Cannot open key reference file\n"); 269 return -1; 270 } 271 272 std::string ref; 273 std::getline(ref_file, ref); 274 std::string policy = std::string() + keyring + "." + ref; 275 INFO("Setting poliy %s\n", policy.c_str()); 276 if (do_policy_set(dir, policy.c_str())) { 277 ERROR("Setting policy on %s failed!", dir); 278 return -1; 279 } 280 281 return 0; 282} 283