Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61addf0d authored by Joshua Duong's avatar Joshua Duong Committed by Gerrit Code Review
Browse files

Merge "Add adbd tls APIs to adbd_auth library."

parents 26b068e9 3d0860e8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ cc_library {

    version_script: "libadbd_auth.map.txt",
    stubs: {
        versions: ["1"],
        versions: ["30"],
        symbol_file: "libadbd_auth.map.txt",
    },

+165 −41
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@

using android::base::unique_fd;

static constexpr uint32_t kAuthVersion = 1;

struct AdbdAuthPacketAuthenticated {
    std::string public_key;
};
@@ -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;
@@ -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";
@@ -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_) {
@@ -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;
@@ -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());
@@ -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));
                            }
                        }
@@ -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;
@@ -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;
                    }
                }
@@ -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;
    }

@@ -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;
@@ -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_;
@@ -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) {
@@ -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) {
@@ -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;
}
+135 −24
Original line number Diff line number Diff line
@@ -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
+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:
    *;
};