Merge "Add fdsan capabilities for native handles" am: 98e474ab43
Original change: https://android-review.googlesource.com/c/platform/system/core/+/2199556 Change-Id: I2a2274988755c33d4eb3719f78bc50638782048b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
aa83e839b0
3 changed files with 121 additions and 33 deletions
|
|
@ -168,6 +168,9 @@ cc_library {
|
||||||
target: {
|
target: {
|
||||||
linux_bionic: {
|
linux_bionic: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
static_libs: [
|
||||||
|
"libasync_safe",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
not_windows: {
|
not_windows: {
|
||||||
srcs: libcutils_nonwindows_sources + [
|
srcs: libcutils_nonwindows_sources + [
|
||||||
|
|
@ -190,6 +193,9 @@ cc_library {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
android: {
|
android: {
|
||||||
|
static_libs: [
|
||||||
|
"libasync_safe",
|
||||||
|
],
|
||||||
srcs: libcutils_nonwindows_sources + [
|
srcs: libcutils_nonwindows_sources + [
|
||||||
"android_reboot.cpp",
|
"android_reboot.cpp",
|
||||||
"ashmem-dev.cpp",
|
"ashmem-dev.cpp",
|
||||||
|
|
|
||||||
|
|
@ -49,18 +49,28 @@ typedef struct native_handle
|
||||||
typedef const native_handle_t* buffer_handle_t;
|
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
|
||||||
* closes the file descriptors contained in this native_handle_t
|
* 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.
|
||||||
|
*
|
||||||
|
* 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
|
* return 0 on success, or a negative error code on failure
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
int native_handle_close(const native_handle_t* h);
|
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
|
* Initializes a native_handle_t from storage. storage must be declared with
|
||||||
* NATIVE_HANDLE_DECLARE_STORAGE. numFds and numInts must not respectively
|
* NATIVE_HANDLE_DECLARE_STORAGE. numFds and numInts must not respectively
|
||||||
* exceed maxFds and maxInts used to declare the storage.
|
* 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_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,
|
* native_handle_delete(). Note that numFds must be <= NATIVE_HANDLE_MAX_FDS,
|
||||||
* numInts must be <= NATIVE_HANDLE_MAX_INTS, and both must be >= 0.
|
* numInts must be <= NATIVE_HANDLE_MAX_INTS, and both must be >= 0.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
native_handle_t* native_handle_create(int numFds, int numInts);
|
native_handle_t* native_handle_create(int numFds, int numInts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* native_handle_clone
|
* 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
|
||||||
* creates a native_handle_t and initializes it from another native_handle_t.
|
* 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().
|
* Must be destroyed with native_handle_delete().
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
native_handle_t* native_handle_clone(const native_handle_t* handle);
|
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
|
* 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().
|
* close the file descriptors; which can be achieved with native_handle_close().
|
||||||
*
|
*
|
||||||
* return 0 on success, or a negative error code on failure
|
* return 0 on success, or a negative error code on failure
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
int native_handle_delete(native_handle_t* h);
|
int native_handle_delete(native_handle_t* h);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,74 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.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) {
|
native_handle_t* native_handle_init(char* storage, int numFds, int numInts) {
|
||||||
if ((uintptr_t) storage % alignof(native_handle_t)) {
|
if ((uintptr_t)storage % alignof(native_handle_t)) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
native_handle_t* handle = (native_handle_t*) storage;
|
native_handle_t* handle = (native_handle_t*)storage;
|
||||||
handle->version = sizeof(native_handle_t);
|
handle->version = sizeof(native_handle_t);
|
||||||
handle->numFds = numFds;
|
handle->numFds = numFds;
|
||||||
handle->numInts = numInts;
|
handle->numInts = numInts;
|
||||||
|
|
@ -52,6 +113,14 @@ native_handle_t* native_handle_create(int numFds, int numInts) {
|
||||||
return h;
|
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* native_handle_clone(const native_handle_t* handle) {
|
||||||
native_handle_t* clone = native_handle_create(handle->numFds, handle->numInts);
|
native_handle_t* clone = native_handle_create(handle->numFds, handle->numInts);
|
||||||
if (clone == NULL) return NULL;
|
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) {
|
int native_handle_close(const native_handle_t* h) {
|
||||||
if (!h) return 0;
|
return close_internal(h, /*allowUntagged=*/true);
|
||||||
|
}
|
||||||
if (h->version != sizeof(native_handle_t)) return -EINVAL;
|
|
||||||
|
int native_handle_close_with_tag(const native_handle_t* h) {
|
||||||
int saved_errno = errno;
|
return close_internal(h, /*allowUntagged=*/false);
|
||||||
const int numFds = h->numFds;
|
|
||||||
for (int i = 0; i < numFds; ++i) {
|
|
||||||
close(h->data[i]);
|
|
||||||
}
|
|
||||||
errno = saved_errno;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue