Add fdsan capabilities for native handles
Introduces new APIs which can be used to simplify application of fdsan to native_handle_t usage, and applies fdsan protection to native_handle_clone() by default. Bug: 244214188 Test: validated alongside sensor service change to use the new APIs Change-Id: I3be16a09c336bcbe880bdb542d5da2969c2c34d3
This commit is contained in:
parent
68e3a6f94a
commit
9f2af69d2a
3 changed files with 121 additions and 33 deletions
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
|
|
|
@ -22,13 +22,74 @@
|
|||
#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)) {
|
||||
if ((uintptr_t)storage % alignof(native_handle_t)) {
|
||||
errno = EINVAL;
|
||||
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->numFds = numFds;
|
||||
handle->numInts = numInts;
|
||||
|
@ -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]);
|
||||
}
|
||||
errno = saved_errno;
|
||||
return 0;
|
||||
return close_internal(h, /*allowUntagged=*/true);
|
||||
}
|
||||
|
||||
int native_handle_close_with_tag(const native_handle_t* h) {
|
||||
return close_internal(h, /*allowUntagged=*/false);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue