Loading libs/adbd_auth/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ cc_library { version_script: "libadbd_auth.map.txt", stubs: { versions: ["1"], versions: ["30"], symbol_file: "libadbd_auth.map.txt", }, Loading libs/adbd_auth/adbd_auth.cpp +165 −41 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ using android::base::unique_fd; static constexpr uint32_t kAuthVersion = 1; struct AdbdAuthPacketAuthenticated { std::string public_key; }; Loading @@ -55,8 +57,21 @@ struct AdbdAuthPacketRequestAuthorization { std::string public_key; }; using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected, AdbdAuthPacketRequestAuthorization>; struct AdbdPacketTlsDeviceConnected { uint8_t transport_type; std::string public_key; }; struct AdbdPacketTlsDeviceDisconnected { uint8_t transport_type; std::string public_key; }; using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected, AdbdAuthPacketRequestAuthorization, AdbdPacketTlsDeviceConnected, AdbdPacketTlsDeviceDisconnected>; struct AdbdAuthContext { static constexpr uint64_t kEpollConstSocket = 0; Loading @@ -65,6 +80,7 @@ struct AdbdAuthContext { public: explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) { InitFrameworkHandlers(); epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); if (epoll_fd_ == -1) { PLOG(FATAL) << "failed to create epoll fd"; Loading Loading @@ -163,34 +179,56 @@ public: } } void HandlePacket(std::string_view packet) REQUIRES(mutex_) { void HandlePacket(std::string_view packet) EXCLUDES(mutex_) { LOG(INFO) << "received packet: " << packet; if (packet.length() < 2) { if (packet.size() < 2) { LOG(ERROR) << "received packet of invalid length"; std::lock_guard<std::mutex> lock(mutex_); ReplaceFrameworkFd(unique_fd()); } bool handled_packet = false; for (size_t i = 0; i < framework_handlers_.size(); ++i) { if (android::base::ConsumePrefix(&packet, framework_handlers_[i].code)) { framework_handlers_[i].cb(packet); handled_packet = true; break; } } if (!handled_packet) { LOG(ERROR) << "unhandled packet: " << packet; std::lock_guard<std::mutex> lock(mutex_); ReplaceFrameworkFd(unique_fd()); } } if (packet[0] == 'O' && packet[1] == 'K') { CHECK(this->dispatched_prompt_.has_value()); auto& [id, key, arg] = *this->dispatched_prompt_; void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) { std::lock_guard<std::mutex> lock(mutex_); CHECK(buf.empty()); CHECK(dispatched_prompt_.has_value()); auto& [id, key, arg] = *dispatched_prompt_; keys_.emplace(id, std::move(key)); this->callbacks_.key_authorized(arg, id); this->dispatched_prompt_ = std::nullopt; callbacks_.key_authorized(arg, id); dispatched_prompt_ = std::nullopt; // We need to dispatch pending prompts here upon success as well, // since we might have multiple queued prompts. DispatchPendingPrompt(); } else if (packet[0] == 'N' && packet[1] == 'O') { CHECK_EQ(2UL, packet.length()); } void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) { std::lock_guard<std::mutex> lock(mutex_); CHECK(buf.empty()); // TODO: Do we want a callback if the key is denied? this->dispatched_prompt_ = std::nullopt; dispatched_prompt_ = std::nullopt; DispatchPendingPrompt(); } else { LOG(ERROR) << "unhandled packet: " << packet; ReplaceFrameworkFd(unique_fd()); } void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) { CHECK(!buf.empty()); callbacks_.key_removed(buf.data(), buf.size()); } bool SendPacket() REQUIRES(mutex_) { Loading @@ -201,7 +239,8 @@ public: CHECK_NE(-1, framework_fd_.get()); auto& packet = output_queue_.front(); struct iovec iovs[2]; struct iovec iovs[3]; int iovcnt = 2; if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) { iovs[0].iov_base = const_cast<char*>("CK"); iovs[0].iov_len = 2; Loading @@ -217,13 +256,29 @@ public: iovs[0].iov_len = 2; iovs[1].iov_base = p->public_key.data(); iovs[1].iov_len = p->public_key.size(); } else if (auto* p = std::get_if<AdbdPacketTlsDeviceConnected>(&packet)) { iovcnt = 3; iovs[0].iov_base = const_cast<char*>("WE"); iovs[0].iov_len = 2; iovs[1].iov_base = &p->transport_type; iovs[1].iov_len = 1; iovs[2].iov_base = p->public_key.data(); iovs[2].iov_len = p->public_key.size(); } else if (auto* p = std::get_if<AdbdPacketTlsDeviceDisconnected>(&packet)) { iovcnt = 3; iovs[0].iov_base = const_cast<char*>("WF"); iovs[0].iov_len = 2; iovs[1].iov_base = &p->transport_type; iovs[1].iov_len = 1; iovs[2].iov_base = p->public_key.data(); iovs[2].iov_len = p->public_key.size(); } else { LOG(FATAL) << "unhandled packet type?"; } output_queue_.pop_front(); ssize_t rc = writev(framework_fd_.get(), iovs, 2); ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt); if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { PLOG(ERROR) << "failed to write to framework fd"; ReplaceFrameworkFd(unique_fd()); Loading Loading @@ -308,7 +363,6 @@ public: std::lock_guard<std::mutex> lock(mutex_); ReplaceFrameworkFd(unique_fd()); } else { std::lock_guard<std::mutex> lock(mutex_); HandlePacket(std::string_view(buf, rc)); } } Loading @@ -329,7 +383,7 @@ public: } static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"}; void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) { void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) { for (const auto& path : key_paths) { if (access(path, R_OK) == 0) { LOG(INFO) << "Loading keys from " << path; Loading @@ -339,7 +393,7 @@ public: continue; } for (const auto& line : android::base::Split(content, "\n")) { if (!callback(line.data(), line.size(), arg)) { if (!callback(opaque, line.data(), line.size())) { return; } } Loading @@ -361,7 +415,7 @@ public: std::lock_guard<std::mutex> lock(mutex_); keys_.emplace(id, public_key); output_queue_.emplace_back( AdbdAuthPacketDisconnected{.public_key = std::string(public_key)}); AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)}); return id; } Loading @@ -376,6 +430,32 @@ public: keys_.erase(it); } uint64_t NotifyTlsDeviceConnected(AdbTransportType type, std::string_view public_key) EXCLUDES(mutex_) { uint64_t id = NextId(); std::lock_guard<std::mutex> lock(mutex_); keys_.emplace(id, public_key); output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{ .transport_type = static_cast<uint8_t>(type), .public_key = std::string(public_key)}); Interrupt(); return id; } void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) { std::lock_guard<std::mutex> lock(mutex_); auto it = keys_.find(id); if (it == keys_.end()) { LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping"; return; } output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{ .transport_type = static_cast<uint8_t>(type), .public_key = std::move(it->second)}); keys_.erase(it); Interrupt(); } // Interrupt the worker thread to do some work. void Interrupt() { uint64_t value = 1; Loading @@ -387,6 +467,24 @@ public: } } void InitFrameworkHandlers() { // Framework wants to disconnect from a secured wifi device framework_handlers_.emplace_back( FrameworkPktHandler{ .code = "DD", .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)}); // Framework allows USB debugging for the device framework_handlers_.emplace_back( FrameworkPktHandler{ .code = "OK", .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)}); // Framework denies USB debugging for the device framework_handlers_.emplace_back( FrameworkPktHandler{ .code = "NO", .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)}); } unique_fd epoll_fd_; unique_fd event_fd_; unique_fd sock_fd_; Loading @@ -400,19 +498,27 @@ public: // We keep two separate queues: one to handle backpressure from the socket (output_queue_) // and one to make sure we only dispatch one authrequest at a time (pending_prompts_). std::deque<AdbdAuthPacket> output_queue_; std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_); std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_); std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_); // This is a list of commands that the framework could send to us. using FrameworkHandlerCb = std::function<void(std::string_view)>; struct FrameworkPktHandler { const char* code; FrameworkHandlerCb cb; }; std::vector<FrameworkPktHandler> framework_handlers_; }; AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) { if (callbacks->version != 1) { if (callbacks->version == 1) { return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks)); } else { LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version; return nullptr; } return new AdbdAuthContext(&callbacks->callbacks.v1); } void adbd_auth_delete(AdbdAuthContext* ctx) { Loading @@ -424,9 +530,9 @@ void adbd_auth_run(AdbdAuthContext* ctx) { } void adbd_auth_get_public_keys(AdbdAuthContext* ctx, bool (*callback)(const char* public_key, size_t len, void* arg), void* arg) { ctx->IteratePublicKeys(callback, arg); bool (*callback)(void* opaque, const char* public_key, size_t len), void* opaque) { ctx->IteratePublicKeys(callback, opaque); } uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) { Loading @@ -438,10 +544,28 @@ void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) { } void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg) { ctx->PromptUser(std::string_view(public_key, len), arg); void* opaque) { ctx->PromptUser(std::string_view(public_key, len), opaque); } uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx, AdbTransportType type, const char* public_key, size_t len) { return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len)); } void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx, AdbTransportType type, uint64_t id) { ctx->NotifyTlsDeviceDisconnected(type, id); } uint32_t adbd_auth_get_max_version() { return kAuthVersion; } bool adbd_auth_supports_feature(AdbdAuthFeature) { bool adbd_auth_supports_feature(AdbdAuthFeature f) { UNUSED(f); return false; } libs/adbd_auth/include/adbd_auth.h +135 −24 Original line number Diff line number Diff line Loading @@ -18,48 +18,159 @@ #include <stdbool.h> #include <stdint.h> #include <sys/cdefs.h> #include <sys/types.h> extern "C" { #if !defined(__INTRODUCED_IN) #define __INTRODUCED_IN(__api_level) /* nothing */ #endif struct AdbdAuthCallbacksV1 { // Callback for a successful user authorization. void (*key_authorized)(void* arg, uint64_t id); __BEGIN_DECLS #if !defined(__ANDROID__) || __ANDROID_API__ >= 30 // The transport type of the device connection. enum AdbTransportType : int32_t { kAdbTransportTypeUsb = 0, kAdbTransportTypeWifi, }; static_assert(sizeof(AdbTransportType) == sizeof(int32_t), "Unexpected AdbTransportType size"); struct AdbdAuthCallbacks { uint32_t version; union { AdbdAuthCallbacksV1 v1; } callbacks; }; struct AdbdAuthCallbacksV1 : AdbdAuthCallbacks { // Callback for a successful user authorization. void (*key_authorized)(void* opaque, uint64_t id); // The framework removed the key from the keystore. This callback notifies // adbd so it can take the appropriate actions (e.g. disconnect all devices // using that key). void (*key_removed)(const char* public_key, size_t length); }; struct AdbdAuthContext; typedef struct AdbdAuthContext AdbdAuthContext; AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks); void adbd_auth_delete(AdbdAuthContext* ctx); /** * Creates a new AdbdAuthContext. * * @param callbacks a set of user-provided callbacks used internally (see * #AdbdAuthCallbacksV1 * @return a new AdbdAuthContext instance. Caller is responsible for destroying * the context with #adbd_auth_delete. */ AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) __INTRODUCED_IN(30); void adbd_auth_run(AdbdAuthContext* ctx); /** * Destroys the AdbdAuthContext. * * @param ctx the AdbdAuthContext to destroy. */ void adbd_auth_delete(AdbdAuthContext* ctx) __INTRODUCED_IN(30); // Iterate through the list of authorized public keys. // Return false from the callback to stop iteration. /** * Starts the AdbdAuthContext. * * The caller may want to run this on a different thread, as this * runs indefinitely. * * @param ctx the AdbdAuthContext */ void adbd_auth_run(AdbdAuthContext* ctx) __INTRODUCED_IN(30); /** * Iterate through the list of authorized public keys. * * @param ctx the AdbdAuthContext * @param callback a callback which will get called for every known adb public * key in its keystore. To stop iteration of the keys, return false in the * callback. Otherwise, return true to continue the iteration. * @param opaque an opaque userdata argument */ void adbd_auth_get_public_keys(AdbdAuthContext* ctx, bool (*callback)(const char* public_key, size_t len, void* arg), void* arg); bool (*callback)(void* opaque, const char* public_key, size_t len), void* opaque) __INTRODUCED_IN(30); /** * Let system_server know that a key has been successfully used for authentication. * * @param ctx the AdbdAuthContext * @param public_key the RSA key that was authorized using the AUTH protocol * @param len the length of the public_key argument * @return an id corresponding to the new connection */ uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) __INTRODUCED_IN(30); // Let system_server know that a key has been successfully used for authentication. uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len); /** * Let system_server know that an AUTH connection has been closed. * * @param ctx the AdbdAuthContext * @param id the id of the disconnected device */ void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) __INTRODUCED_IN(30); // Let system_server know that a connection has been closed. void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id); /** * Prompt the user to authorize a public key. * * When this happens, a callback will be run on the auth thread with the result. * * @param ctx the AdbdAuthContext * @param public_key the RSA public key to prompt user with * @param len the length of the public_key argument * @param arg an opaque userdata argument */ void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* opaque) __INTRODUCED_IN(30); // Prompt the user to authorize a public key. // When this happens, a callback will be run on the auth thread with the result. void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg); /** * Let system_server know that a TLS device has connected. * * @param ctx the AdbdAuthContext * @param type the transport type of the connection (see #AdbTransportType) * @param public_key the RSA public key used to establish the connection * @param len the length of the public_key argument * @return an id corresponding to the new connection */ uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx, AdbTransportType type, const char* public_key, size_t len) __INTRODUCED_IN(30); enum AdbdAuthFeature { /** * Let system_server know that a TLS device has disconnected. * * @param ctx the AdbdAuthContext * @param type the transport type of the connection (see #AdbTransportType) * @param the id of the disconnected device (see #adbd_tls_device_connected) */ void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx, AdbTransportType type, uint64_t id) __INTRODUCED_IN(30); /** * Returns the max #AdbdAuthCallbacks version. * * The version starts at 1, with version 1 corresponding to the * #AdbdAuthCallbacksV1 struct. * * @return the max #AdbdAuthCallbacks version. */ uint32_t adbd_auth_get_max_version(void) __INTRODUCED_IN(30); enum AdbdAuthFeature : int32_t { }; bool adbd_auth_supports_feature(AdbdAuthFeature f); /** * Checks if a feature is supported by the framework. See #AdbdAuthFeature. * * @param feature the feature to check for support * @return true if the feature is supported */ bool adbd_auth_supports_feature(AdbdAuthFeature feature); } #endif //!__ANDROID__ || __ANDROID_API__ >= 30 __END_DECLS libs/adbd_auth/libadbd_auth.map.txt +11 −8 Original line number Diff line number Diff line LIBADBD_AUTH { global: adbd_auth_new; # apex adbd_auth_delete; # apex adbd_auth_run; # apex adbd_auth_get_public_keys; #apex adbd_auth_notify_auth; # apex adbd_auth_notify_disconnect; # apex adbd_auth_prompt_user; # apex adbd_auth_supports_feature; # apex adbd_auth_new; # apex introduced=30 adbd_auth_delete; # apex introduced=30 adbd_auth_run; # apex introduced=30 adbd_auth_get_public_keys; #apex introduced=30 adbd_auth_notify_auth; # apex introduced=30 adbd_auth_notify_disconnect; # apex introduced=30 adbd_auth_prompt_user; # apex introduced=30 adbd_auth_tls_device_connected; # apex introduced=30 adbd_auth_tls_device_disconnected; # apex introduced=30 adbd_auth_get_max_version; # apex introduced=30 adbd_auth_supports_feature; # apex introduced=30 local: *; }; Loading
libs/adbd_auth/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ cc_library { version_script: "libadbd_auth.map.txt", stubs: { versions: ["1"], versions: ["30"], symbol_file: "libadbd_auth.map.txt", }, Loading
libs/adbd_auth/adbd_auth.cpp +165 −41 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ using android::base::unique_fd; static constexpr uint32_t kAuthVersion = 1; struct AdbdAuthPacketAuthenticated { std::string public_key; }; Loading @@ -55,8 +57,21 @@ struct AdbdAuthPacketRequestAuthorization { std::string public_key; }; using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected, AdbdAuthPacketRequestAuthorization>; struct AdbdPacketTlsDeviceConnected { uint8_t transport_type; std::string public_key; }; struct AdbdPacketTlsDeviceDisconnected { uint8_t transport_type; std::string public_key; }; using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected, AdbdAuthPacketRequestAuthorization, AdbdPacketTlsDeviceConnected, AdbdPacketTlsDeviceDisconnected>; struct AdbdAuthContext { static constexpr uint64_t kEpollConstSocket = 0; Loading @@ -65,6 +80,7 @@ struct AdbdAuthContext { public: explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) { InitFrameworkHandlers(); epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); if (epoll_fd_ == -1) { PLOG(FATAL) << "failed to create epoll fd"; Loading Loading @@ -163,34 +179,56 @@ public: } } void HandlePacket(std::string_view packet) REQUIRES(mutex_) { void HandlePacket(std::string_view packet) EXCLUDES(mutex_) { LOG(INFO) << "received packet: " << packet; if (packet.length() < 2) { if (packet.size() < 2) { LOG(ERROR) << "received packet of invalid length"; std::lock_guard<std::mutex> lock(mutex_); ReplaceFrameworkFd(unique_fd()); } bool handled_packet = false; for (size_t i = 0; i < framework_handlers_.size(); ++i) { if (android::base::ConsumePrefix(&packet, framework_handlers_[i].code)) { framework_handlers_[i].cb(packet); handled_packet = true; break; } } if (!handled_packet) { LOG(ERROR) << "unhandled packet: " << packet; std::lock_guard<std::mutex> lock(mutex_); ReplaceFrameworkFd(unique_fd()); } } if (packet[0] == 'O' && packet[1] == 'K') { CHECK(this->dispatched_prompt_.has_value()); auto& [id, key, arg] = *this->dispatched_prompt_; void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) { std::lock_guard<std::mutex> lock(mutex_); CHECK(buf.empty()); CHECK(dispatched_prompt_.has_value()); auto& [id, key, arg] = *dispatched_prompt_; keys_.emplace(id, std::move(key)); this->callbacks_.key_authorized(arg, id); this->dispatched_prompt_ = std::nullopt; callbacks_.key_authorized(arg, id); dispatched_prompt_ = std::nullopt; // We need to dispatch pending prompts here upon success as well, // since we might have multiple queued prompts. DispatchPendingPrompt(); } else if (packet[0] == 'N' && packet[1] == 'O') { CHECK_EQ(2UL, packet.length()); } void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) { std::lock_guard<std::mutex> lock(mutex_); CHECK(buf.empty()); // TODO: Do we want a callback if the key is denied? this->dispatched_prompt_ = std::nullopt; dispatched_prompt_ = std::nullopt; DispatchPendingPrompt(); } else { LOG(ERROR) << "unhandled packet: " << packet; ReplaceFrameworkFd(unique_fd()); } void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) { CHECK(!buf.empty()); callbacks_.key_removed(buf.data(), buf.size()); } bool SendPacket() REQUIRES(mutex_) { Loading @@ -201,7 +239,8 @@ public: CHECK_NE(-1, framework_fd_.get()); auto& packet = output_queue_.front(); struct iovec iovs[2]; struct iovec iovs[3]; int iovcnt = 2; if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) { iovs[0].iov_base = const_cast<char*>("CK"); iovs[0].iov_len = 2; Loading @@ -217,13 +256,29 @@ public: iovs[0].iov_len = 2; iovs[1].iov_base = p->public_key.data(); iovs[1].iov_len = p->public_key.size(); } else if (auto* p = std::get_if<AdbdPacketTlsDeviceConnected>(&packet)) { iovcnt = 3; iovs[0].iov_base = const_cast<char*>("WE"); iovs[0].iov_len = 2; iovs[1].iov_base = &p->transport_type; iovs[1].iov_len = 1; iovs[2].iov_base = p->public_key.data(); iovs[2].iov_len = p->public_key.size(); } else if (auto* p = std::get_if<AdbdPacketTlsDeviceDisconnected>(&packet)) { iovcnt = 3; iovs[0].iov_base = const_cast<char*>("WF"); iovs[0].iov_len = 2; iovs[1].iov_base = &p->transport_type; iovs[1].iov_len = 1; iovs[2].iov_base = p->public_key.data(); iovs[2].iov_len = p->public_key.size(); } else { LOG(FATAL) << "unhandled packet type?"; } output_queue_.pop_front(); ssize_t rc = writev(framework_fd_.get(), iovs, 2); ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt); if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { PLOG(ERROR) << "failed to write to framework fd"; ReplaceFrameworkFd(unique_fd()); Loading Loading @@ -308,7 +363,6 @@ public: std::lock_guard<std::mutex> lock(mutex_); ReplaceFrameworkFd(unique_fd()); } else { std::lock_guard<std::mutex> lock(mutex_); HandlePacket(std::string_view(buf, rc)); } } Loading @@ -329,7 +383,7 @@ public: } static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"}; void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) { void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) { for (const auto& path : key_paths) { if (access(path, R_OK) == 0) { LOG(INFO) << "Loading keys from " << path; Loading @@ -339,7 +393,7 @@ public: continue; } for (const auto& line : android::base::Split(content, "\n")) { if (!callback(line.data(), line.size(), arg)) { if (!callback(opaque, line.data(), line.size())) { return; } } Loading @@ -361,7 +415,7 @@ public: std::lock_guard<std::mutex> lock(mutex_); keys_.emplace(id, public_key); output_queue_.emplace_back( AdbdAuthPacketDisconnected{.public_key = std::string(public_key)}); AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)}); return id; } Loading @@ -376,6 +430,32 @@ public: keys_.erase(it); } uint64_t NotifyTlsDeviceConnected(AdbTransportType type, std::string_view public_key) EXCLUDES(mutex_) { uint64_t id = NextId(); std::lock_guard<std::mutex> lock(mutex_); keys_.emplace(id, public_key); output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{ .transport_type = static_cast<uint8_t>(type), .public_key = std::string(public_key)}); Interrupt(); return id; } void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) { std::lock_guard<std::mutex> lock(mutex_); auto it = keys_.find(id); if (it == keys_.end()) { LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping"; return; } output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{ .transport_type = static_cast<uint8_t>(type), .public_key = std::move(it->second)}); keys_.erase(it); Interrupt(); } // Interrupt the worker thread to do some work. void Interrupt() { uint64_t value = 1; Loading @@ -387,6 +467,24 @@ public: } } void InitFrameworkHandlers() { // Framework wants to disconnect from a secured wifi device framework_handlers_.emplace_back( FrameworkPktHandler{ .code = "DD", .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)}); // Framework allows USB debugging for the device framework_handlers_.emplace_back( FrameworkPktHandler{ .code = "OK", .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)}); // Framework denies USB debugging for the device framework_handlers_.emplace_back( FrameworkPktHandler{ .code = "NO", .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)}); } unique_fd epoll_fd_; unique_fd event_fd_; unique_fd sock_fd_; Loading @@ -400,19 +498,27 @@ public: // We keep two separate queues: one to handle backpressure from the socket (output_queue_) // and one to make sure we only dispatch one authrequest at a time (pending_prompts_). std::deque<AdbdAuthPacket> output_queue_; std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_); std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_); std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_); // This is a list of commands that the framework could send to us. using FrameworkHandlerCb = std::function<void(std::string_view)>; struct FrameworkPktHandler { const char* code; FrameworkHandlerCb cb; }; std::vector<FrameworkPktHandler> framework_handlers_; }; AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) { if (callbacks->version != 1) { if (callbacks->version == 1) { return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks)); } else { LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version; return nullptr; } return new AdbdAuthContext(&callbacks->callbacks.v1); } void adbd_auth_delete(AdbdAuthContext* ctx) { Loading @@ -424,9 +530,9 @@ void adbd_auth_run(AdbdAuthContext* ctx) { } void adbd_auth_get_public_keys(AdbdAuthContext* ctx, bool (*callback)(const char* public_key, size_t len, void* arg), void* arg) { ctx->IteratePublicKeys(callback, arg); bool (*callback)(void* opaque, const char* public_key, size_t len), void* opaque) { ctx->IteratePublicKeys(callback, opaque); } uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) { Loading @@ -438,10 +544,28 @@ void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) { } void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg) { ctx->PromptUser(std::string_view(public_key, len), arg); void* opaque) { ctx->PromptUser(std::string_view(public_key, len), opaque); } uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx, AdbTransportType type, const char* public_key, size_t len) { return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len)); } void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx, AdbTransportType type, uint64_t id) { ctx->NotifyTlsDeviceDisconnected(type, id); } uint32_t adbd_auth_get_max_version() { return kAuthVersion; } bool adbd_auth_supports_feature(AdbdAuthFeature) { bool adbd_auth_supports_feature(AdbdAuthFeature f) { UNUSED(f); return false; }
libs/adbd_auth/include/adbd_auth.h +135 −24 Original line number Diff line number Diff line Loading @@ -18,48 +18,159 @@ #include <stdbool.h> #include <stdint.h> #include <sys/cdefs.h> #include <sys/types.h> extern "C" { #if !defined(__INTRODUCED_IN) #define __INTRODUCED_IN(__api_level) /* nothing */ #endif struct AdbdAuthCallbacksV1 { // Callback for a successful user authorization. void (*key_authorized)(void* arg, uint64_t id); __BEGIN_DECLS #if !defined(__ANDROID__) || __ANDROID_API__ >= 30 // The transport type of the device connection. enum AdbTransportType : int32_t { kAdbTransportTypeUsb = 0, kAdbTransportTypeWifi, }; static_assert(sizeof(AdbTransportType) == sizeof(int32_t), "Unexpected AdbTransportType size"); struct AdbdAuthCallbacks { uint32_t version; union { AdbdAuthCallbacksV1 v1; } callbacks; }; struct AdbdAuthCallbacksV1 : AdbdAuthCallbacks { // Callback for a successful user authorization. void (*key_authorized)(void* opaque, uint64_t id); // The framework removed the key from the keystore. This callback notifies // adbd so it can take the appropriate actions (e.g. disconnect all devices // using that key). void (*key_removed)(const char* public_key, size_t length); }; struct AdbdAuthContext; typedef struct AdbdAuthContext AdbdAuthContext; AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks); void adbd_auth_delete(AdbdAuthContext* ctx); /** * Creates a new AdbdAuthContext. * * @param callbacks a set of user-provided callbacks used internally (see * #AdbdAuthCallbacksV1 * @return a new AdbdAuthContext instance. Caller is responsible for destroying * the context with #adbd_auth_delete. */ AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) __INTRODUCED_IN(30); void adbd_auth_run(AdbdAuthContext* ctx); /** * Destroys the AdbdAuthContext. * * @param ctx the AdbdAuthContext to destroy. */ void adbd_auth_delete(AdbdAuthContext* ctx) __INTRODUCED_IN(30); // Iterate through the list of authorized public keys. // Return false from the callback to stop iteration. /** * Starts the AdbdAuthContext. * * The caller may want to run this on a different thread, as this * runs indefinitely. * * @param ctx the AdbdAuthContext */ void adbd_auth_run(AdbdAuthContext* ctx) __INTRODUCED_IN(30); /** * Iterate through the list of authorized public keys. * * @param ctx the AdbdAuthContext * @param callback a callback which will get called for every known adb public * key in its keystore. To stop iteration of the keys, return false in the * callback. Otherwise, return true to continue the iteration. * @param opaque an opaque userdata argument */ void adbd_auth_get_public_keys(AdbdAuthContext* ctx, bool (*callback)(const char* public_key, size_t len, void* arg), void* arg); bool (*callback)(void* opaque, const char* public_key, size_t len), void* opaque) __INTRODUCED_IN(30); /** * Let system_server know that a key has been successfully used for authentication. * * @param ctx the AdbdAuthContext * @param public_key the RSA key that was authorized using the AUTH protocol * @param len the length of the public_key argument * @return an id corresponding to the new connection */ uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) __INTRODUCED_IN(30); // Let system_server know that a key has been successfully used for authentication. uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len); /** * Let system_server know that an AUTH connection has been closed. * * @param ctx the AdbdAuthContext * @param id the id of the disconnected device */ void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) __INTRODUCED_IN(30); // Let system_server know that a connection has been closed. void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id); /** * Prompt the user to authorize a public key. * * When this happens, a callback will be run on the auth thread with the result. * * @param ctx the AdbdAuthContext * @param public_key the RSA public key to prompt user with * @param len the length of the public_key argument * @param arg an opaque userdata argument */ void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* opaque) __INTRODUCED_IN(30); // Prompt the user to authorize a public key. // When this happens, a callback will be run on the auth thread with the result. void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg); /** * Let system_server know that a TLS device has connected. * * @param ctx the AdbdAuthContext * @param type the transport type of the connection (see #AdbTransportType) * @param public_key the RSA public key used to establish the connection * @param len the length of the public_key argument * @return an id corresponding to the new connection */ uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx, AdbTransportType type, const char* public_key, size_t len) __INTRODUCED_IN(30); enum AdbdAuthFeature { /** * Let system_server know that a TLS device has disconnected. * * @param ctx the AdbdAuthContext * @param type the transport type of the connection (see #AdbTransportType) * @param the id of the disconnected device (see #adbd_tls_device_connected) */ void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx, AdbTransportType type, uint64_t id) __INTRODUCED_IN(30); /** * Returns the max #AdbdAuthCallbacks version. * * The version starts at 1, with version 1 corresponding to the * #AdbdAuthCallbacksV1 struct. * * @return the max #AdbdAuthCallbacks version. */ uint32_t adbd_auth_get_max_version(void) __INTRODUCED_IN(30); enum AdbdAuthFeature : int32_t { }; bool adbd_auth_supports_feature(AdbdAuthFeature f); /** * Checks if a feature is supported by the framework. See #AdbdAuthFeature. * * @param feature the feature to check for support * @return true if the feature is supported */ bool adbd_auth_supports_feature(AdbdAuthFeature feature); } #endif //!__ANDROID__ || __ANDROID_API__ >= 30 __END_DECLS
libs/adbd_auth/libadbd_auth.map.txt +11 −8 Original line number Diff line number Diff line LIBADBD_AUTH { global: adbd_auth_new; # apex adbd_auth_delete; # apex adbd_auth_run; # apex adbd_auth_get_public_keys; #apex adbd_auth_notify_auth; # apex adbd_auth_notify_disconnect; # apex adbd_auth_prompt_user; # apex adbd_auth_supports_feature; # apex adbd_auth_new; # apex introduced=30 adbd_auth_delete; # apex introduced=30 adbd_auth_run; # apex introduced=30 adbd_auth_get_public_keys; #apex introduced=30 adbd_auth_notify_auth; # apex introduced=30 adbd_auth_notify_disconnect; # apex introduced=30 adbd_auth_prompt_user; # apex introduced=30 adbd_auth_tls_device_connected; # apex introduced=30 adbd_auth_tls_device_disconnected; # apex introduced=30 adbd_auth_get_max_version; # apex introduced=30 adbd_auth_supports_feature; # apex introduced=30 local: *; };