Loading adb/adb_auth.cpp +5 −8 Original line number Diff line number Diff line Loading @@ -64,12 +64,14 @@ static void send_auth_publickey(atransport* t) { p->msg.command = A_AUTH; p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; p->msg.data_length = key.size(); // adbd expects a null-terminated string. p->msg.data_length = key.size() + 1; send_packet(p, t); } void send_auth_response(uint8_t* token, size_t token_size, atransport* t) { RSA* key = t->NextKey(); std::shared_ptr<RSA> key = t->NextKey(); if (key == nullptr) { // No more private keys to try, send the public key. send_auth_publickey(t); Loading @@ -79,12 +81,7 @@ void send_auth_response(uint8_t* token, size_t token_size, atransport* t) { LOG(INFO) << "Calling send_auth_response"; apacket* p = get_apacket(); int ret = adb_auth_sign(key, token, token_size, p->data); // Stop sharing this key. RSA_free(key); key = nullptr; int ret = adb_auth_sign(key.get(), token, token_size, p->data); if (!ret) { D("Error signing the token"); put_apacket(p); Loading adb/adb_auth.h +3 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "adb.h" #include <deque> #include <memory> #include <openssl/rsa.h> Loading @@ -43,7 +44,7 @@ void send_auth_response(uint8_t *token, size_t token_size, atransport *t); void adb_auth_init(); int adb_auth_sign(RSA* key, const unsigned char* token, size_t token_size, unsigned char* sig); std::string adb_auth_get_userkey(); std::deque<RSA*> adb_auth_get_private_keys(); std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys(); static inline bool adb_auth_generate_token(void*, size_t) { abort(); } static inline bool adb_auth_verify(void*, size_t, void*, int) { abort(); } Loading @@ -53,7 +54,7 @@ static inline void adb_auth_confirm_key(unsigned char*, size_t, atransport*) { a static inline int adb_auth_sign(void*, const unsigned char*, size_t, unsigned char*) { abort(); } static inline std::string adb_auth_get_userkey() { abort(); } static inline std::deque<RSA*> adb_auth_get_private_keys() { abort(); } static inline std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() { abort(); } void adbd_auth_init(void); void adbd_cloexec_auth_socket(); Loading adb/adb_auth_host.cpp +181 −26 Original line number Diff line number Diff line Loading @@ -16,16 +16,18 @@ #define TRACE_TAG AUTH #include "adb_auth.h" #include "adb.h" #include "adb_utils.h" #include "sysdeps.h" #include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #if defined(__linux__) #include <sys/inotify.h> #endif #include <map> #include <mutex> #include <set> #include <string> #include <android-base/errors.h> #include <android-base/file.h> Loading @@ -39,10 +41,16 @@ #include <openssl/rsa.h> #include <openssl/sha.h> #include "adb.h" #include "adb_auth.h" #include "adb_utils.h" #include "sysdeps.h" #include "sysdeps/mutex.h" static std::mutex& g_key_list_mutex = *new std::mutex; static std::deque<RSA*>& g_key_list = *new std::deque<RSA*>; static std::mutex& g_keys_mutex = *new std::mutex; static std::map<std::string, std::shared_ptr<RSA>>& g_keys = *new std::map<std::string, std::shared_ptr<RSA>>; static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>; static std::string get_user_info() { LOG(INFO) << "get_user_info..."; Loading Loading @@ -146,8 +154,23 @@ out: return ret; } static bool read_key(const std::string& file) { LOG(INFO) << "read_key '" << file << "'..."; static std::string hash_key(RSA* key) { unsigned char* pubkey = nullptr; int len = i2d_RSA_PUBKEY(key, &pubkey); if (len < 0) { LOG(ERROR) << "failed to encode RSA public key"; return std::string(); } std::string result; result.resize(SHA256_DIGEST_LENGTH); SHA256(pubkey, len, reinterpret_cast<unsigned char*>(&result[0])); OPENSSL_free(pubkey); return result; } static bool read_key_file(const std::string& file) { LOG(INFO) << "read_key_file '" << file << "'..."; std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose); if (!fp) { Loading @@ -162,10 +185,66 @@ static bool read_key(const std::string& file) { return false; } g_key_list.push_back(key); std::lock_guard<std::mutex> lock(g_keys_mutex); std::string fingerprint = hash_key(key); if (g_keys.find(fingerprint) != g_keys.end()) { LOG(INFO) << "ignoring already-loaded key: " << file; RSA_free(key); } else { g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free); } return true; } static bool read_keys(const std::string& path, bool allow_dir = true) { LOG(INFO) << "read_keys '" << path << "'..."; struct stat st; if (stat(path.c_str(), &st) != 0) { PLOG(ERROR) << "failed to stat '" << path << "'"; return false; } if (S_ISREG(st.st_mode)) { if (!android::base::EndsWith(path, ".adb_key")) { LOG(INFO) << "skipping non-adb_key '" << path << "'"; return false; } return read_key_file(path); } else if (S_ISDIR(st.st_mode)) { if (!allow_dir) { // inotify isn't recursive. It would break expectations to load keys in nested // directories but not monitor them for new keys. LOG(WARNING) << "refusing to recurse into directory '" << path << "'"; return false; } std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir); if (!dir) { PLOG(ERROR) << "failed to open directory '" << path << "'"; return false; } bool result = false; while (struct dirent* dent = readdir(dir.get())) { std::string name = dent->d_name; // We can't use dent->d_type here because it's not available on Windows. if (name == "." || name == "..") { continue; } result |= read_keys((path + OS_PATH_SEPARATOR + name).c_str(), false); } return result; } LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode; return false; } static std::string get_user_key_path() { const std::string home = adb_get_homedir_path(true); LOG(DEBUG) << "adb_get_homedir_path returned '" << home << "'"; Loading Loading @@ -200,31 +279,29 @@ static bool get_user_key() { } } return read_key(path); return read_key_file(path); } static void get_vendor_keys() { static std::set<std::string> get_vendor_keys() { const char* adb_keys_path = getenv("ADB_VENDOR_KEYS"); if (adb_keys_path == nullptr) { return; return std::set<std::string>(); } std::set<std::string> result; for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) { if (!read_key(path.c_str())) { PLOG(ERROR) << "Failed to read '" << path << "'"; } result.emplace(path); } return result; } std::deque<RSA*> adb_auth_get_private_keys() { std::deque<RSA*> result; std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() { std::deque<std::shared_ptr<RSA>> result; // Copy all the currently known keys, increasing their reference count so they're // usable until both we and the caller have freed our pointers. std::lock_guard<std::mutex> lock(g_key_list_mutex); for (const auto& key : g_key_list) { RSA_up_ref(key); // Since we're handing out another pointer to this key... result.push_back(key); // Copy all the currently known keys. std::lock_guard<std::mutex> lock(g_keys_mutex); for (const auto& it : g_keys) { result.push_back(it.second); } // Add a sentinel to the list. Our caller uses this to mean "out of private keys, Loading Loading @@ -270,6 +347,77 @@ int adb_auth_keygen(const char* filename) { return (generate_key(filename) == 0); } #if defined(__linux__) static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) { LOG(INFO) << "adb_auth_inotify_update called"; if (!(fd_event & FDE_READ)) { return; } char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; while (true) { ssize_t rc = TEMP_FAILURE_RETRY(unix_read(fd, buf, sizeof(buf))); if (rc == -1) { if (errno == EAGAIN) { LOG(INFO) << "done reading inotify fd"; break; } PLOG(FATAL) << "read of inotify event failed"; } // The read potentially returned multiple events. char* start = buf; char* end = buf + rc; while (start < end) { inotify_event* event = reinterpret_cast<inotify_event*>(start); auto root_it = g_monitored_paths.find(event->wd); if (root_it == g_monitored_paths.end()) { LOG(FATAL) << "observed inotify event for unmonitored path, wd = " << event->wd; } std::string path = root_it->second; if (event->len > 0) { path += '/'; path += event->name; } if (event->mask & (IN_CREATE | IN_MOVED_TO)) { if (event->mask & IN_ISDIR) { LOG(INFO) << "ignoring new directory at '" << path << "'"; } else { LOG(INFO) << "observed new file at '" << path << "'"; read_keys(path, false); } } else { LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex << event->mask; } start += sizeof(struct inotify_event) + event->len; } } } static void adb_auth_inotify_init(const std::set<std::string>& paths) { LOG(INFO) << "adb_auth_inotify_init..."; int infd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); for (const std::string& path : paths) { int wd = inotify_add_watch(infd, path.c_str(), IN_CREATE | IN_MOVED_TO); if (wd < 0) { PLOG(ERROR) << "failed to inotify_add_watch on path '" << path; continue; } g_monitored_paths[wd] = path; LOG(INFO) << "watch descriptor " << wd << " registered for " << path; } fdevent* event = fdevent_create(infd, adb_auth_inotify_update, nullptr); fdevent_add(event, FDE_READ); } #endif void adb_auth_init() { LOG(INFO) << "adb_auth_init..."; Loading @@ -278,6 +426,13 @@ void adb_auth_init() { return; } std::lock_guard<std::mutex> lock(g_key_list_mutex); get_vendor_keys(); const auto& key_paths = get_vendor_keys(); #if defined(__linux__) adb_auth_inotify_init(key_paths); #endif for (const std::string& path : key_paths) { read_keys(path.c_str()); } } adb/transport.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -1076,10 +1076,10 @@ int check_data(apacket *p) } } RSA* atransport::NextKey() { std::shared_ptr<RSA> atransport::NextKey() { if (keys_.empty()) keys_ = adb_auth_get_private_keys(); RSA* result = keys_[0]; std::shared_ptr<RSA> result = keys_[0]; keys_.pop_front(); return result; } adb/transport.h +3 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <deque> #include <list> #include <memory> #include <string> #include <unordered_set> Loading Loading @@ -107,7 +108,7 @@ public: return type == kTransportLocal && local_port_for_emulator_ == -1; } RSA* NextKey(); std::shared_ptr<RSA> NextKey(); unsigned char token[TOKEN_SIZE] = {}; size_t failed_auth_attempts = 0; Loading Loading @@ -160,7 +161,7 @@ private: // A list of adisconnect callbacks called when the transport is kicked. std::list<adisconnect*> disconnects_; std::deque<RSA*> keys_; std::deque<std::shared_ptr<RSA>> keys_; DISALLOW_COPY_AND_ASSIGN(atransport); }; Loading Loading
adb/adb_auth.cpp +5 −8 Original line number Diff line number Diff line Loading @@ -64,12 +64,14 @@ static void send_auth_publickey(atransport* t) { p->msg.command = A_AUTH; p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; p->msg.data_length = key.size(); // adbd expects a null-terminated string. p->msg.data_length = key.size() + 1; send_packet(p, t); } void send_auth_response(uint8_t* token, size_t token_size, atransport* t) { RSA* key = t->NextKey(); std::shared_ptr<RSA> key = t->NextKey(); if (key == nullptr) { // No more private keys to try, send the public key. send_auth_publickey(t); Loading @@ -79,12 +81,7 @@ void send_auth_response(uint8_t* token, size_t token_size, atransport* t) { LOG(INFO) << "Calling send_auth_response"; apacket* p = get_apacket(); int ret = adb_auth_sign(key, token, token_size, p->data); // Stop sharing this key. RSA_free(key); key = nullptr; int ret = adb_auth_sign(key.get(), token, token_size, p->data); if (!ret) { D("Error signing the token"); put_apacket(p); Loading
adb/adb_auth.h +3 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "adb.h" #include <deque> #include <memory> #include <openssl/rsa.h> Loading @@ -43,7 +44,7 @@ void send_auth_response(uint8_t *token, size_t token_size, atransport *t); void adb_auth_init(); int adb_auth_sign(RSA* key, const unsigned char* token, size_t token_size, unsigned char* sig); std::string adb_auth_get_userkey(); std::deque<RSA*> adb_auth_get_private_keys(); std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys(); static inline bool adb_auth_generate_token(void*, size_t) { abort(); } static inline bool adb_auth_verify(void*, size_t, void*, int) { abort(); } Loading @@ -53,7 +54,7 @@ static inline void adb_auth_confirm_key(unsigned char*, size_t, atransport*) { a static inline int adb_auth_sign(void*, const unsigned char*, size_t, unsigned char*) { abort(); } static inline std::string adb_auth_get_userkey() { abort(); } static inline std::deque<RSA*> adb_auth_get_private_keys() { abort(); } static inline std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() { abort(); } void adbd_auth_init(void); void adbd_cloexec_auth_socket(); Loading
adb/adb_auth_host.cpp +181 −26 Original line number Diff line number Diff line Loading @@ -16,16 +16,18 @@ #define TRACE_TAG AUTH #include "adb_auth.h" #include "adb.h" #include "adb_utils.h" #include "sysdeps.h" #include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #if defined(__linux__) #include <sys/inotify.h> #endif #include <map> #include <mutex> #include <set> #include <string> #include <android-base/errors.h> #include <android-base/file.h> Loading @@ -39,10 +41,16 @@ #include <openssl/rsa.h> #include <openssl/sha.h> #include "adb.h" #include "adb_auth.h" #include "adb_utils.h" #include "sysdeps.h" #include "sysdeps/mutex.h" static std::mutex& g_key_list_mutex = *new std::mutex; static std::deque<RSA*>& g_key_list = *new std::deque<RSA*>; static std::mutex& g_keys_mutex = *new std::mutex; static std::map<std::string, std::shared_ptr<RSA>>& g_keys = *new std::map<std::string, std::shared_ptr<RSA>>; static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>; static std::string get_user_info() { LOG(INFO) << "get_user_info..."; Loading Loading @@ -146,8 +154,23 @@ out: return ret; } static bool read_key(const std::string& file) { LOG(INFO) << "read_key '" << file << "'..."; static std::string hash_key(RSA* key) { unsigned char* pubkey = nullptr; int len = i2d_RSA_PUBKEY(key, &pubkey); if (len < 0) { LOG(ERROR) << "failed to encode RSA public key"; return std::string(); } std::string result; result.resize(SHA256_DIGEST_LENGTH); SHA256(pubkey, len, reinterpret_cast<unsigned char*>(&result[0])); OPENSSL_free(pubkey); return result; } static bool read_key_file(const std::string& file) { LOG(INFO) << "read_key_file '" << file << "'..."; std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose); if (!fp) { Loading @@ -162,10 +185,66 @@ static bool read_key(const std::string& file) { return false; } g_key_list.push_back(key); std::lock_guard<std::mutex> lock(g_keys_mutex); std::string fingerprint = hash_key(key); if (g_keys.find(fingerprint) != g_keys.end()) { LOG(INFO) << "ignoring already-loaded key: " << file; RSA_free(key); } else { g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free); } return true; } static bool read_keys(const std::string& path, bool allow_dir = true) { LOG(INFO) << "read_keys '" << path << "'..."; struct stat st; if (stat(path.c_str(), &st) != 0) { PLOG(ERROR) << "failed to stat '" << path << "'"; return false; } if (S_ISREG(st.st_mode)) { if (!android::base::EndsWith(path, ".adb_key")) { LOG(INFO) << "skipping non-adb_key '" << path << "'"; return false; } return read_key_file(path); } else if (S_ISDIR(st.st_mode)) { if (!allow_dir) { // inotify isn't recursive. It would break expectations to load keys in nested // directories but not monitor them for new keys. LOG(WARNING) << "refusing to recurse into directory '" << path << "'"; return false; } std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir); if (!dir) { PLOG(ERROR) << "failed to open directory '" << path << "'"; return false; } bool result = false; while (struct dirent* dent = readdir(dir.get())) { std::string name = dent->d_name; // We can't use dent->d_type here because it's not available on Windows. if (name == "." || name == "..") { continue; } result |= read_keys((path + OS_PATH_SEPARATOR + name).c_str(), false); } return result; } LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode; return false; } static std::string get_user_key_path() { const std::string home = adb_get_homedir_path(true); LOG(DEBUG) << "adb_get_homedir_path returned '" << home << "'"; Loading Loading @@ -200,31 +279,29 @@ static bool get_user_key() { } } return read_key(path); return read_key_file(path); } static void get_vendor_keys() { static std::set<std::string> get_vendor_keys() { const char* adb_keys_path = getenv("ADB_VENDOR_KEYS"); if (adb_keys_path == nullptr) { return; return std::set<std::string>(); } std::set<std::string> result; for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) { if (!read_key(path.c_str())) { PLOG(ERROR) << "Failed to read '" << path << "'"; } result.emplace(path); } return result; } std::deque<RSA*> adb_auth_get_private_keys() { std::deque<RSA*> result; std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys() { std::deque<std::shared_ptr<RSA>> result; // Copy all the currently known keys, increasing their reference count so they're // usable until both we and the caller have freed our pointers. std::lock_guard<std::mutex> lock(g_key_list_mutex); for (const auto& key : g_key_list) { RSA_up_ref(key); // Since we're handing out another pointer to this key... result.push_back(key); // Copy all the currently known keys. std::lock_guard<std::mutex> lock(g_keys_mutex); for (const auto& it : g_keys) { result.push_back(it.second); } // Add a sentinel to the list. Our caller uses this to mean "out of private keys, Loading Loading @@ -270,6 +347,77 @@ int adb_auth_keygen(const char* filename) { return (generate_key(filename) == 0); } #if defined(__linux__) static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) { LOG(INFO) << "adb_auth_inotify_update called"; if (!(fd_event & FDE_READ)) { return; } char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; while (true) { ssize_t rc = TEMP_FAILURE_RETRY(unix_read(fd, buf, sizeof(buf))); if (rc == -1) { if (errno == EAGAIN) { LOG(INFO) << "done reading inotify fd"; break; } PLOG(FATAL) << "read of inotify event failed"; } // The read potentially returned multiple events. char* start = buf; char* end = buf + rc; while (start < end) { inotify_event* event = reinterpret_cast<inotify_event*>(start); auto root_it = g_monitored_paths.find(event->wd); if (root_it == g_monitored_paths.end()) { LOG(FATAL) << "observed inotify event for unmonitored path, wd = " << event->wd; } std::string path = root_it->second; if (event->len > 0) { path += '/'; path += event->name; } if (event->mask & (IN_CREATE | IN_MOVED_TO)) { if (event->mask & IN_ISDIR) { LOG(INFO) << "ignoring new directory at '" << path << "'"; } else { LOG(INFO) << "observed new file at '" << path << "'"; read_keys(path, false); } } else { LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex << event->mask; } start += sizeof(struct inotify_event) + event->len; } } } static void adb_auth_inotify_init(const std::set<std::string>& paths) { LOG(INFO) << "adb_auth_inotify_init..."; int infd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); for (const std::string& path : paths) { int wd = inotify_add_watch(infd, path.c_str(), IN_CREATE | IN_MOVED_TO); if (wd < 0) { PLOG(ERROR) << "failed to inotify_add_watch on path '" << path; continue; } g_monitored_paths[wd] = path; LOG(INFO) << "watch descriptor " << wd << " registered for " << path; } fdevent* event = fdevent_create(infd, adb_auth_inotify_update, nullptr); fdevent_add(event, FDE_READ); } #endif void adb_auth_init() { LOG(INFO) << "adb_auth_init..."; Loading @@ -278,6 +426,13 @@ void adb_auth_init() { return; } std::lock_guard<std::mutex> lock(g_key_list_mutex); get_vendor_keys(); const auto& key_paths = get_vendor_keys(); #if defined(__linux__) adb_auth_inotify_init(key_paths); #endif for (const std::string& path : key_paths) { read_keys(path.c_str()); } }
adb/transport.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -1076,10 +1076,10 @@ int check_data(apacket *p) } } RSA* atransport::NextKey() { std::shared_ptr<RSA> atransport::NextKey() { if (keys_.empty()) keys_ = adb_auth_get_private_keys(); RSA* result = keys_[0]; std::shared_ptr<RSA> result = keys_[0]; keys_.pop_front(); return result; }
adb/transport.h +3 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <deque> #include <list> #include <memory> #include <string> #include <unordered_set> Loading Loading @@ -107,7 +108,7 @@ public: return type == kTransportLocal && local_port_for_emulator_ == -1; } RSA* NextKey(); std::shared_ptr<RSA> NextKey(); unsigned char token[TOKEN_SIZE] = {}; size_t failed_auth_attempts = 0; Loading Loading @@ -160,7 +161,7 @@ private: // A list of adisconnect callbacks called when the transport is kicked. std::list<adisconnect*> disconnects_; std::deque<RSA*> keys_; std::deque<std::shared_ptr<RSA>> keys_; DISALLOW_COPY_AND_ASSIGN(atransport); }; Loading