302 lines
9.5 KiB
Diff
302 lines
9.5 KiB
Diff
From 973f9e5f37695c73d75450bd555149dda40bdfed Mon Sep 17 00:00:00 2001
|
|
From: Ziyang Zhou <ziyang.zhou@outlook.com>
|
|
Date: Sun, 3 Jul 2022 11:22:31 +0800
|
|
Subject: [PATCH 6/7] memfd support
|
|
|
|
---
|
|
libcutils/Android.bp | 2 +-
|
|
libcutils/ashmem-dev.cpp | 47 +++++++++++
|
|
libcutils/ashmem-hack.inc | 172 ++++++++++++++++++++++++++++++++++++++
|
|
3 files changed, 220 insertions(+), 1 deletion(-)
|
|
create mode 100644 libcutils/ashmem-hack.inc
|
|
|
|
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
|
|
index bcc9b1c84..8c825d9b4 100644
|
|
--- a/libcutils/Android.bp
|
|
+++ b/libcutils/Android.bp
|
|
@@ -171,7 +171,7 @@ cc_library {
|
|
}
|
|
},
|
|
|
|
- shared_libs: ["liblog"],
|
|
+ shared_libs: ["liblog", "libbase"],
|
|
header_libs: [
|
|
"libcutils_headers",
|
|
"libutils_headers",
|
|
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
|
|
index 15ace0e64..30ac6db86 100644
|
|
--- a/libcutils/ashmem-dev.cpp
|
|
+++ b/libcutils/ashmem-dev.cpp
|
|
@@ -135,8 +135,14 @@ static int __ashmem_is_ashmem(int fd, int fatal)
|
|
return -1;
|
|
}
|
|
|
|
+#include "ashmem-hack.inc"
|
|
+
|
|
int ashmem_valid(int fd)
|
|
{
|
|
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
return __ashmem_is_ashmem(fd, 0) >= 0;
|
|
}
|
|
|
|
@@ -151,6 +157,10 @@ int ashmem_create_region(const char *name, size_t size)
|
|
{
|
|
int ret, save_errno;
|
|
|
|
+ if (has_memfd_support()) {
|
|
+ return memfd_create_region(name ? name : "none", size);
|
|
+ }
|
|
+
|
|
int fd = __ashmem_open();
|
|
if (fd < 0) {
|
|
return fd;
|
|
@@ -182,6 +192,10 @@ error:
|
|
|
|
int ashmem_set_prot_region(int fd, int prot)
|
|
{
|
|
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
|
|
+ return memfd_set_prot_region(fd, prot);
|
|
+ }
|
|
+
|
|
int ret = __ashmem_is_ashmem(fd, 1);
|
|
if (ret < 0) {
|
|
return ret;
|
|
@@ -192,6 +206,15 @@ int ashmem_set_prot_region(int fd, int prot)
|
|
|
|
int ashmem_pin_region(int fd, size_t offset, size_t len)
|
|
{
|
|
+ if (!pin_deprecation_warn || debug_log) {
|
|
+ ALOGE("Pinning is deprecated since Android Q. Please use trim or other methods.\n");
|
|
+ pin_deprecation_warn = true;
|
|
+ }
|
|
+
|
|
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
// TODO: should LP64 reject too-large offset/len?
|
|
ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
|
|
|
|
@@ -205,6 +228,15 @@ int ashmem_pin_region(int fd, size_t offset, size_t len)
|
|
|
|
int ashmem_unpin_region(int fd, size_t offset, size_t len)
|
|
{
|
|
+ if (!pin_deprecation_warn || debug_log) {
|
|
+ ALOGE("Pinning is deprecated since Android Q. Please use trim or other methods.\n");
|
|
+ pin_deprecation_warn = true;
|
|
+ }
|
|
+
|
|
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
// TODO: should LP64 reject too-large offset/len?
|
|
ashmem_pin pin = { static_cast<uint32_t>(offset), static_cast<uint32_t>(len) };
|
|
|
|
@@ -218,6 +250,21 @@ int ashmem_unpin_region(int fd, size_t offset, size_t len)
|
|
|
|
int ashmem_get_size_region(int fd)
|
|
{
|
|
+ if (has_memfd_support() && !memfd_is_ashmem(fd)) {
|
|
+ struct stat sb;
|
|
+
|
|
+ if (fstat(fd, &sb) == -1) {
|
|
+ ALOGE("ashmem_get_size_region(%d): fstat failed: %s\n", fd, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (debug_log) {
|
|
+ ALOGD("ashmem_get_size_region(%d): %d\n", fd, static_cast<int>(sb.st_size));
|
|
+ }
|
|
+
|
|
+ return sb.st_size;
|
|
+ }
|
|
+
|
|
int ret = __ashmem_is_ashmem(fd, 1);
|
|
if (ret < 0) {
|
|
return ret;
|
|
diff --git a/libcutils/ashmem-hack.inc b/libcutils/ashmem-hack.inc
|
|
new file mode 100644
|
|
index 000000000..8526c85be
|
|
--- /dev/null
|
|
+++ b/libcutils/ashmem-hack.inc
|
|
@@ -0,0 +1,172 @@
|
|
+/*
|
|
+ * Copyright (C) 2008 The Android Open Source Project
|
|
+ *
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
+ * you may not use this file except in compliance with the License.
|
|
+ * You may obtain a copy of the License at
|
|
+ *
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
+ *
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
+ * See the License for the specific language governing permissions and
|
|
+ * limitations under the License.
|
|
+ */
|
|
+
|
|
+#include <cutils/ashmem.h>
|
|
+
|
|
+#include <errno.h>
|
|
+#include <fcntl.h>
|
|
+#include <linux/ashmem.h>
|
|
+#include <linux/memfd.h>
|
|
+#include <log/log.h>
|
|
+#include <pthread.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/mman.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/syscall.h>
|
|
+#include <sys/sysmacros.h>
|
|
+#include <sys/types.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include <android-base/file.h>
|
|
+#include <android-base/properties.h>
|
|
+#include <android-base/strings.h>
|
|
+#include <android-base/unique_fd.h>
|
|
+
|
|
+/* Will be added to UAPI once upstream change is merged */
|
|
+#define F_SEAL_FUTURE_WRITE 0x0010
|
|
+
|
|
+/*
|
|
+ * The minimum vendor API level at and after which it is safe to use memfd.
|
|
+ * This is to facilitate deprecation of ashmem.
|
|
+ */
|
|
+#define MIN_MEMFD_VENDOR_API_LEVEL 29
|
|
+#define MIN_MEMFD_VENDOR_API_LEVEL_CHAR 'Q'
|
|
+
|
|
+/*
|
|
+ * has_memfd_support() determines if the device can use memfd. memfd support
|
|
+ * has been there for long time, but certain things in it may be missing. We
|
|
+ * check for needed support in it. Also we check if the VNDK version of
|
|
+ * libcutils being used is new enough, if its not, then we cannot use memfd
|
|
+ * since the older copies may be using ashmem so we just use ashmem. Once all
|
|
+ * Android devices that are getting updates are new enough (ex, they were
|
|
+ * originally shipped with Android release > P), then we can just use memfd and
|
|
+ * delete all ashmem code from libcutils (while preserving the interface).
|
|
+ *
|
|
+ * NOTE:
|
|
+ * The sys.use_memfd property is set by default to false in Android
|
|
+ * to temporarily disable memfd, till vendor and apps are ready for it.
|
|
+ * The main issue: either apps or vendor processes can directly make ashmem
|
|
+ * IOCTLs on FDs they receive by assuming they are ashmem, without going
|
|
+ * through libcutils. Such fds could have very well be originally created with
|
|
+ * libcutils hence they could be memfd. Thus the IOCTLs will break.
|
|
+ *
|
|
+ * Set default value of sys.use_memfd property to true once the issue is
|
|
+ * resolved, so that the code can then self-detect if kernel support is present
|
|
+ * on the device. The property can also set to true from adb shell, for
|
|
+ * debugging.
|
|
+ */
|
|
+
|
|
+static bool debug_log = false; /* set to true for verbose logging and other debug */
|
|
+static bool pin_deprecation_warn = true; /* Log the pin deprecation warning only once */
|
|
+
|
|
+
|
|
+/* Determine if memfd can be supported. This is just one-time hardwork
|
|
+ * which will be cached by the caller.
|
|
+ */
|
|
+static bool __has_memfd_support() {
|
|
+ /* Used to turn on/off the detection at runtime, in the future this
|
|
+ * property will be removed once we switch everything over to ashmem.
|
|
+ * Currently it is used only for debugging to switch the system over.
|
|
+ */
|
|
+ if (!android::base::GetBoolProperty("sys.use_memfd", false)) {
|
|
+ if (debug_log) {
|
|
+ ALOGD("sys.use_memfd=false so memfd disabled\n");
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // Check if kernel support exists, otherwise fall back to ashmem.
|
|
+ // This code needs to build on old API levels, so we can't use the libc
|
|
+ // wrapper.
|
|
+ android::base::unique_fd fd(
|
|
+ syscall(__NR_memfd_create, "test_android_memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING));
|
|
+ if (fd == -1) {
|
|
+ ALOGE("memfd_create failed: %s, no memfd support.\n", strerror(errno));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) {
|
|
+ ALOGE("fcntl(F_ADD_SEALS) failed: %s, no memfd support.\n", strerror(errno));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (debug_log) {
|
|
+ ALOGD("memfd: device has memfd support, using it\n");
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static bool has_memfd_support() {
|
|
+ /* memfd_supported is the initial global per-process state of what is known
|
|
+ * about memfd.
|
|
+ */
|
|
+ static bool memfd_supported = __has_memfd_support();
|
|
+
|
|
+ return memfd_supported;
|
|
+}
|
|
+
|
|
+static bool memfd_is_ashmem(int fd) {
|
|
+ static bool fd_check_error_once = false;
|
|
+
|
|
+ if (__ashmem_is_ashmem(fd, 0) == 0) {
|
|
+ if (!fd_check_error_once) {
|
|
+ ALOGE("memfd: memfd expected but ashmem fd used - please use libcutils.\n");
|
|
+ fd_check_error_once = true;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static int memfd_create_region(const char* name, size_t size) {
|
|
+ // This code needs to build on old API levels, so we can't use the libc
|
|
+ // wrapper.
|
|
+ android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_CLOEXEC | MFD_ALLOW_SEALING));
|
|
+
|
|
+ if (fd == -1) {
|
|
+ ALOGE("memfd_create(%s, %zd) failed: %s\n", name, size, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (ftruncate(fd, size) == -1) {
|
|
+ ALOGE("ftruncate(%s, %zd) failed for memfd creation: %s\n", name, size, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (debug_log) {
|
|
+ ALOGE("memfd_create(%s, %zd) success. fd=%d\n", name, size, fd.get());
|
|
+ }
|
|
+ return fd.release();
|
|
+}
|
|
+
|
|
+static int memfd_set_prot_region(int fd, int prot) {
|
|
+ /* Only proceed if an fd needs to be write-protected */
|
|
+ if (prot & PROT_WRITE) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE) == -1) {
|
|
+ ALOGE("memfd_set_prot_region(%d, %d): F_SEAL_FUTURE_WRITE seal failed: %s\n", fd, prot,
|
|
+ strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
--
|
|
2.34.1
|
|
|