ext4_crypt_init_extensions.cpp revision 883d7a7d08cae35d8a1479c4d5b40d2d8fa3ff5c
1#define TAG "ext4_utils" 2 3#include "ext4_crypt_init_extensions.h" 4 5#include <string> 6 7#include <dirent.h> 8#include <errno.h> 9#include <sys/mount.h> 10#include <sys/stat.h> 11#include <unistd.h> 12 13#include <cutils/klog.h> 14#include <cutils/properties.h> 15#include <cutils/sockets.h> 16#include <poll.h> 17 18#include "key_control.h" 19#include "unencrypted_properties.h" 20 21static const std::string arbitrary_sequence_number = "42"; 22static const int vold_command_timeout_ms = 60 * 1000; 23 24static std::string vold_command(std::string const& command) 25{ 26 KLOG_INFO(TAG, "Running command %s\n", command.c_str()); 27 int sock = -1; 28 29 while (true) { 30 sock = socket_local_client("cryptd", 31 ANDROID_SOCKET_NAMESPACE_RESERVED, 32 SOCK_STREAM); 33 if (sock >= 0) { 34 break; 35 } 36 usleep(10000); 37 } 38 39 if (sock < 0) { 40 KLOG_INFO(TAG, "Cannot open vold, failing command (%s)\n", strerror(errno)); 41 return ""; 42 } 43 44 class CloseSocket 45 { 46 int sock_; 47 public: 48 CloseSocket(int sock) : sock_(sock) {} 49 ~CloseSocket() { close(sock_); } 50 }; 51 52 CloseSocket cs(sock); 53 54 // Use arbitrary sequence number. This should only be used when the 55 // framework is down, so this is (mostly) OK. 56 std::string actual_command = arbitrary_sequence_number + " " + command; 57 if (write(sock, actual_command.c_str(), actual_command.size() + 1) < 0) { 58 KLOG_ERROR(TAG, "Cannot write command (%s)\n", strerror(errno)); 59 return ""; 60 } 61 62 struct pollfd poll_sock = {sock, POLLIN, 0}; 63 64 int rc = TEMP_FAILURE_RETRY(poll(&poll_sock, 1, vold_command_timeout_ms)); 65 if (rc < 0) { 66 KLOG_ERROR(TAG, "Error in poll (%s)\n", strerror(errno)); 67 return ""; 68 } 69 70 if (!(poll_sock.revents & POLLIN)) { 71 KLOG_ERROR(TAG, "Timeout\n"); 72 return ""; 73 } 74 char buffer[4096]; 75 memset(buffer, 0, sizeof(buffer)); 76 rc = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer))); 77 if (rc <= 0) { 78 if (rc == 0) { 79 KLOG_ERROR(TAG, "Lost connection to Vold - did it crash?\n"); 80 } else { 81 KLOG_ERROR(TAG, "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 94int e4crypt_create_device_key(const char* dir, 95 int ensure_dir_exists(const char*)) 96{ 97 // Already encrypted with password? If so bail 98 std::string temp_folder = std::string() + dir + "/tmp_mnt"; 99 DIR* temp_dir = opendir(temp_folder.c_str()); 100 if (temp_dir) { 101 closedir(temp_dir); 102 return 0; 103 } 104 105 // Make sure folder exists. Use make_dir to set selinux permissions. 106 if (ensure_dir_exists(UnencryptedProperties::GetPath(dir).c_str())) { 107 KLOG_ERROR(TAG, "Failed to create %s (%s)\n", 108 UnencryptedProperties::GetPath(dir).c_str(), 109 strerror(errno)); 110 return -1; 111 } 112 113 auto result = vold_command("cryptfs enablefilecrypto"); 114 // ext4enc:TODO proper error handling 115 KLOG_INFO(TAG, "enablefilecrypto returned with result %s\n", 116 result.c_str()); 117 118 return 0; 119} 120 121int e4crypt_install_keyring() 122{ 123 key_serial_t device_keyring = add_key("keyring", "e4crypt", 0, 0, 124 KEY_SPEC_SESSION_KEYRING); 125 126 if (device_keyring == -1) { 127 KLOG_ERROR(TAG, "Failed to create keyring (%s)\n", strerror(errno)); 128 return -1; 129 } 130 131 KLOG_INFO(TAG, "Keyring created wth id %d in process %d\n", 132 device_keyring, getpid()); 133 134 return 0; 135} 136 137int e4crypt_set_directory_policy(const char* dir) 138{ 139 // Only set policy on first level /data directories 140 // To make this less restrictive, consider using a policy file. 141 // However this is overkill for as long as the policy is simply 142 // to apply a global policy to all /data folders created via makedir 143 if (!dir || strncmp(dir, "/data/", 6) || strchr(dir + 6, '/')) { 144 return 0; 145 } 146 147 // Don't encrypt lost+found - ext4 doesn't like it 148 if (!strcmp(dir, "/data/lost+found")) { 149 return 0; 150 } 151 152 // ext4enc:TODO exclude /data/user with a horrible special case. 153 if (!strcmp(dir, "/data/user")) { 154 return 0; 155 } 156 157 UnencryptedProperties props("/data"); 158 std::string policy = props.Get<std::string>(properties::ref); 159 if (policy.empty()) { 160 // ext4enc:TODO why is this OK? 161 return 0; 162 } 163 164 KLOG_INFO(TAG, "Setting policy on %s\n", dir); 165 int result = do_policy_set(dir, policy.c_str(), policy.size()); 166 if (result) { 167 KLOG_ERROR(TAG, "Setting %02x%02x%02x%02x policy on %s failed!\n", 168 policy[0], policy[1], policy[2], policy[3], dir); 169 return -1; 170 } 171 172 return 0; 173} 174 175int e4crypt_set_user_crypto_policies(const char* dir) 176{ 177 auto command = std::string() + "cryptfs setusercryptopolicies " + dir; 178 auto result = vold_command(command); 179 // ext4enc:TODO proper error handling 180 KLOG_INFO(TAG, "setusercryptopolicies returned with result %s\n", 181 result.c_str()); 182 return 0; 183} 184