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
diff --git a/libcutils/native_handle.cpp b/libcutils/native_handle.cpp
index 5804ab1..b85c93b 100644
--- a/libcutils/native_handle.cpp
+++ b/libcutils/native_handle.cpp
@@ -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 @@
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_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 saved_errno = errno;
- const int numFds = h->numFds;
- for (int i = 0; i < numFds; ++i) {
- close(h->data[i]);
- }
- errno = saved_errno;
- return 0;
+int native_handle_close_with_tag(const native_handle_t* h) {
+ return close_internal(h, /*allowUntagged=*/false);
}