diff --git a/third_party/ashmem/ashmem-dev.c b/third_party/ashmem/ashmem-dev.c index 4a3e31f6910f4..7713e6f892dd8 100644 --- a/third_party/ashmem/ashmem-dev.c +++ b/third_party/ashmem/ashmem-dev.c @@ -27,12 +27,15 @@ #include #include #include /* for fdstat() */ +#include #include +#include #include #include #define ASHMEM_DEVICE "/dev/ashmem" +#define LOG_E(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "chromium-ashmem", __VA_ARGS__)) /* Technical note regarding reading system properties. * @@ -75,6 +78,13 @@ static int device_api_level() { return s_api_level; } +static int vendor_api_level() { + static int v_api_level = -1; + if (v_api_level < 0) + v_api_level = system_property_get_int("ro.vendor.api_level"); + return v_api_level; +} + typedef enum { ASHMEM_STATUS_INIT, ASHMEM_STATUS_NOT_SUPPORTED, @@ -187,13 +197,55 @@ typedef struct { static ASharedMemoryFuncs s_ashmem_funcs = {}; static pthread_once_t s_ashmem_funcs_once = PTHREAD_ONCE_INIT; +static int memfd_create_region(const char *name, size_t size) { + int fd = syscall(__NR_memfd_create, name, MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd < 0) { + LOG_E("memfd_create(%s, %zd) failed: %m", name, size); + return fd; + } + + int ret = ftruncate(fd, size); + if (ret < 0) { + LOG_E("ftruncate(%s, %zd) failed: %m", name, size); + goto error; + } + + ret = fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK); + if (ret < 0) { + LOG_E("memfd_create(%s, %zd) fcntl(F_ADD_SEALS) failed: %m", name, size); + goto error; + } + + return fd; + +error: + close(fd); + return ret; +} + static void ashmem_init_funcs() { ASharedMemoryFuncs* funcs = &s_ashmem_funcs; if (device_api_level() >= __ANDROID_API_O__) { /* Leaked intentionally! */ void* lib = dlopen("libandroid.so", RTLD_NOW); - funcs->create = - (ASharedMemory_createFunc)dlsym(lib, "ASharedMemory_create"); + /* + * When a device conforms to the VSR for API level 202604 (Android 17), + * ASharedMemory will allocate memfds and attempt to relabel them by using + * fsetxattr() to workaround how SELinux handles memfds. + * + * fsetxattr() is not allowlisted in our seccomp filter, and allowlisting + * it may be unsafe. Since memfds from Chromium should be accessible with + * the existing sepolicy for appdomain_tmpfs files, just allocate memfds + * directly if the device conforms to the VSR for API level 202604. + * + * The rest of the functions work fine with ASharedMemory, as it can recognize + * memfds and act accordingly. + */ + if (vendor_api_level() >= 202604) + funcs->create = &memfd_create_region; + else + funcs->create = + (ASharedMemory_createFunc)dlsym(lib, "ASharedMemory_create"); funcs->getSize = (ASharedMemory_getSizeFunc)dlsym(lib, "ASharedMemory_getSize"); funcs->setProt =