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

Commit 98e474ab authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add fdsan capabilities for native handles"

parents c113dc3a 9f2af69d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -168,6 +168,9 @@ cc_library {
    target: {
        linux_bionic: {
            enabled: true,
            static_libs: [
                "libasync_safe",
            ],
        },
        not_windows: {
            srcs: libcutils_nonwindows_sources + [
@@ -190,6 +193,9 @@ cc_library {
            ],
        },
        android: {
            static_libs: [
                "libasync_safe",
            ],
            srcs: libcutils_nonwindows_sources + [
                "android_reboot.cpp",
                "ashmem-dev.cpp",
+39 −20
Original line number Diff line number Diff line
@@ -49,18 +49,28 @@ typedef struct native_handle
typedef const native_handle_t* buffer_handle_t;

/*
 * native_handle_close
 * Closes the file descriptors contained in this native_handle_t, which may
 * either be untagged or tagged for ownership by this native_handle_t via
 * native_handle_set_tag(). Mixing untagged and tagged fds in the same
 * native_handle_t is not permitted and triggers an fdsan exception, but
 * native_handle_set_fdsan_tag() can be used to bring consistency if this is
 * intentional.
 *
 * closes the file descriptors contained in this native_handle_t
 * If it's known that fds are tagged, prefer native_handle_close_with_tag() for
 * better safety.
 *
 * return 0 on success, or a negative error code on failure
 * 
 */
int native_handle_close(const native_handle_t* h);

/*
 * native_handle_init
 *
 * Equivalent to native_handle_close(), but throws an fdsan exception if the fds
 * are untagged. Use if it's known that the fds in this native_handle_t were
 * previously tagged via native_handle_set_tag().
 */
int native_handle_close_with_tag(const native_handle_t* h);

/*
 * Initializes a native_handle_t from storage.  storage must be declared with
 * NATIVE_HANDLE_DECLARE_STORAGE.  numFds and numInts must not respectively
 * exceed maxFds and maxInts used to declare the storage.
@@ -68,33 +78,42 @@ int native_handle_close(const native_handle_t* h);
native_handle_t* native_handle_init(char* storage, int numFds, int numInts);

/*
 * native_handle_create
 *
 * creates a native_handle_t and initializes it. must be destroyed with
 * Creates a native_handle_t and initializes it. Must be destroyed with
 * native_handle_delete(). Note that numFds must be <= NATIVE_HANDLE_MAX_FDS,
 * numInts must be <= NATIVE_HANDLE_MAX_INTS, and both must be >= 0.
 *
 */
native_handle_t* native_handle_create(int numFds, int numInts);

/*
 * native_handle_clone
 *
 * creates a native_handle_t and initializes it from another native_handle_t.
 * Updates the fdsan tag for any file descriptors contained in the supplied
 * handle to indicate that they are owned by this handle and should only be
 * closed via native_handle_close()/native_handle_close_with_tag(). Each fd in
 * the handle must have a tag of either 0 (unset) or the tag associated with
 * this handle, otherwise an fdsan exception will be triggered.
 */
void native_handle_set_fdsan_tag(const native_handle_t* handle);

/*
 * Clears the fdsan tag for any file descriptors contained in the supplied
 * native_handle_t. Use if this native_handle_t is giving up ownership of its
 * fds, but the fdsan tags were previously set. Each fd in the handle must have
 * a tag of either 0 (unset) or the tag associated with this handle, otherwise
 * an fdsan exception will be triggered.
 */
void native_handle_unset_fdsan_tag(const native_handle_t* handle);

/*
 * Creates a native_handle_t and initializes it from another native_handle_t.
 * Must be destroyed with native_handle_delete().
 *
 */
native_handle_t* native_handle_clone(const native_handle_t* handle);

/*
 * native_handle_delete
 * 
 * frees a native_handle_t allocated with native_handle_create().
 * Frees a native_handle_t allocated with native_handle_create().
 * This ONLY frees the memory allocated for the native_handle_t, but doesn't
 * close the file descriptors; which can be achieved with native_handle_close().
 *
 * return 0 on success, or a negative error code on failure
 * 
 */
int native_handle_delete(native_handle_t* h);

+75 −12
Original line number Diff line number Diff line
@@ -22,6 +22,67 @@
#include <string.h>
#include <unistd.h>

// Needs to come after stdlib includes to capture the __BIONIC__ definition
#ifdef __BIONIC__
#include <android/fdsan.h>
#endif

namespace {

#if !defined(__BIONIC__)
// fdsan stubs when not linked against bionic
#define ANDROID_FDSAN_OWNER_TYPE_NATIVE_HANDLE 0

uint64_t android_fdsan_create_owner_tag(int /*type*/, uint64_t /*tag*/) {
    return 0;
}
uint64_t android_fdsan_get_owner_tag(int /*fd*/) {
    return 0;
}
int android_fdsan_close_with_tag(int fd, uint64_t /*tag*/) {
    return close(fd);
}
void android_fdsan_exchange_owner_tag(int /*fd*/, uint64_t /*expected_tag*/, uint64_t /*tag*/) {}
#endif  // !__BIONIC__

uint64_t get_fdsan_tag(const native_handle_t* handle) {
    return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_NATIVE_HANDLE,
                                          reinterpret_cast<uint64_t>(handle));
}

int close_internal(const native_handle_t* h, bool allowUntagged) {
    if (!h) return 0;

    if (h->version != sizeof(native_handle_t)) return -EINVAL;

    const int numFds = h->numFds;
    uint64_t tag;
    if (allowUntagged && numFds > 0 && android_fdsan_get_owner_tag(h->data[0]) == 0) {
        tag = 0;
    } else {
        tag = get_fdsan_tag(h);
    }
    int saved_errno = errno;
    for (int i = 0; i < numFds; ++i) {
        android_fdsan_close_with_tag(h->data[i], tag);
    }
    errno = saved_errno;
    return 0;
}

void swap_fdsan_tags(const native_handle_t* handle, uint64_t expected_tag, uint64_t new_tag) {
    if (!handle || handle->version != sizeof(native_handle_t)) return;

    for (int i = 0; i < handle->numFds; i++) {
        // allow for idempotence to make the APIs easier to use
        if (android_fdsan_get_owner_tag(handle->data[i]) != new_tag) {
            android_fdsan_exchange_owner_tag(handle->data[i], expected_tag, new_tag);
        }
    }
}

}  // anonymous namespace

native_handle_t* native_handle_init(char* storage, int numFds, int numInts) {
    if ((uintptr_t)storage % alignof(native_handle_t)) {
        errno = EINVAL;
@@ -52,6 +113,14 @@ native_handle_t* native_handle_create(int numFds, int numInts) {
    return h;
}

void native_handle_set_fdsan_tag(const native_handle_t* handle) {
    swap_fdsan_tags(handle, 0, get_fdsan_tag(handle));
}

void native_handle_unset_fdsan_tag(const native_handle_t* handle) {
    swap_fdsan_tags(handle, get_fdsan_tag(handle), 0);
}

native_handle_t* native_handle_clone(const native_handle_t* handle) {
    native_handle_t* clone = native_handle_create(handle->numFds, handle->numInts);
    if (clone == NULL) return NULL;
@@ -81,15 +150,9 @@ int native_handle_delete(native_handle_t* h) {
}

int native_handle_close(const native_handle_t* h) {
    if (!h) return 0;

    if (h->version != sizeof(native_handle_t)) return -EINVAL;

    int saved_errno = errno;
    const int numFds = h->numFds;
    for (int i = 0; i < numFds; ++i) {
        close(h->data[i]);
    return close_internal(h, /*allowUntagged=*/true);
}
    errno = saved_errno;
    return 0;

int native_handle_close_with_tag(const native_handle_t* h) {
    return close_internal(h, /*allowUntagged=*/false);
}