Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6020d41 authored by Atneya Nair's avatar Atneya Nair Committed by Automerger Merge Worker
Browse files

Merge "Add explicit memfd support to MemoryHeapBase" am: 5eb0dcd9 am: 440c4434 am: 2b621d1f

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1851674

Change-Id: I55b257fd89cb9b8d197213eb0187760a223c4caf
parents e1c6809d 2b621d1f
Loading
Loading
Loading
Loading
+56 −8
Original line number Original line Diff line number Diff line
@@ -18,10 +18,13 @@


#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <fcntl.h>
#include <linux/memfd.h>
#include <stdint.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>


@@ -34,6 +37,24 @@ namespace android {


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------


#ifdef __BIONIC__
static int memfd_create_region(const char* name, size_t size) {
    int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
    if (fd == -1) {
        ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno));
        return -1;
    }

    if (ftruncate(fd, size) == -1) {
        ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size,
              strerror(errno));
        close(fd);
        return -1;
    }
    return fd;
}
#endif

MemoryHeapBase::MemoryHeapBase()
MemoryHeapBase::MemoryHeapBase()
    : mFD(-1), mSize(0), mBase(MAP_FAILED),
    : mFD(-1), mSize(0), mBase(MAP_FAILED),
      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
@@ -46,14 +67,35 @@ MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
{
{
    const size_t pagesize = getpagesize();
    const size_t pagesize = getpagesize();
    size = ((size + pagesize - 1) & ~(pagesize - 1));
    size = ((size + pagesize - 1) & ~(pagesize - 1));
    int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
    int fd = -1;
    ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
    if (mFlags & FORCE_MEMFD) {
    if (fd >= 0) {
#ifdef __BIONIC__
        if (mapfd(fd, true, size) == NO_ERROR) {
        ALOGV("MemoryHeapBase: Attempting to force MemFD");
            if (flags & READ_ONLY) {
        fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
                ashmem_set_prot_region(fd, PROT_READ);
        if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
        const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) |
                ((mFlags & MEMFD_ALLOW_SEALING) ? 0 : F_SEAL_SEAL);
        if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
            ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error  %s", name,
                  SEAL_FLAGS, strerror(errno));
            munmap(mBase, mSize);
            mBase = nullptr;
            mSize = 0;
            close(fd);
        }
        }
        return;
#else
        mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING);
#endif
    }
    }
    if (mFlags & MEMFD_ALLOW_SEALING) {
      LOG_ALWAYS_FATAL("Invalid Flags. MEMFD_ALLOW_SEALING only valid with FORCE_MEMFD.");
    }
    fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
    ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
    if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
    if (mFlags & READ_ONLY) {
        ashmem_set_prot_region(fd, PROT_READ);
    }
    }
}
}


@@ -61,6 +103,9 @@ MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
{
    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
        LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
    }
    int open_flags = O_RDWR;
    int open_flags = O_RDWR;
    if (flags & NO_CACHING)
    if (flags & NO_CACHING)
        open_flags |= O_SYNC;
        open_flags |= O_SYNC;
@@ -80,6 +125,9 @@ MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
{
    if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
        LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
    }
    const size_t pagesize = getpagesize();
    const size_t pagesize = getpagesize();
    size = ((size + pagesize-1) & ~(pagesize-1));
    size = ((size + pagesize-1) & ~(pagesize-1));
    mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
    mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
+15 −1
Original line number Original line Diff line number Diff line
@@ -34,7 +34,21 @@ public:
        // memory won't be mapped locally, but will be mapped in the remote
        // memory won't be mapped locally, but will be mapped in the remote
        // process.
        // process.
        DONT_MAP_LOCALLY = 0x00000100,
        DONT_MAP_LOCALLY = 0x00000100,
        NO_CACHING = 0x00000200
        NO_CACHING = 0x00000200,
        // Bypass ashmem-libcutils to create a memfd shared region.
        // Ashmem-libcutils will eventually migrate to memfd.
        // Memfd has security benefits and supports file sealing.
        // Calling process will need to modify selinux permissions to
        // open access to tmpfs files. See audioserver for examples.
        // This is only valid for size constructor.
        // For host compilation targets, memfd is stubbed in favor of /tmp
        // files so sealing is not enforced.
        FORCE_MEMFD = 0x00000400,
        // Default opt-out of sealing behavior in memfd to avoid potential DOS.
        // Clients of shared files can seal at anytime via syscall, leading to
        // TOC/TOU issues if additional seals prevent access from the creating
        // process. Alternatively, seccomp fcntl().
        MEMFD_ALLOW_SEALING = 0x00000800
    };
    };


    /*
    /*
+1 −0
Original line number Original line Diff line number Diff line
@@ -99,6 +99,7 @@ cc_test {
        "binderParcelUnitTest.cpp",
        "binderParcelUnitTest.cpp",
        "binderBinderUnitTest.cpp",
        "binderBinderUnitTest.cpp",
        "binderStatusUnitTest.cpp",
        "binderStatusUnitTest.cpp",
        "binderMemoryHeapBaseUnitTest.cpp",
    ],
    ],
    shared_libs: [
    shared_libs: [
        "libbinder",
        "libbinder",
+97 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 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 <binder/MemoryHeapBase.h>
#include <cutils/ashmem.h>
#include <fcntl.h>

#include <gtest/gtest.h>
using namespace android;
#ifdef __BIONIC__
TEST(MemoryHeapBase, ForceMemfdRespected) {
    auto mHeap = sp<MemoryHeapBase>::make(10, MemoryHeapBase::FORCE_MEMFD, "Test mapping");
    int fd = mHeap->getHeapID();
    EXPECT_NE(fd, -1);
    EXPECT_FALSE(ashmem_valid(fd));
    EXPECT_NE(fcntl(fd, F_GET_SEALS), -1);
}

TEST(MemoryHeapBase, MemfdSealed) {
    auto mHeap = sp<MemoryHeapBase>::make(8192,
                                          MemoryHeapBase::FORCE_MEMFD,
                                          "Test mapping");
    int fd = mHeap->getHeapID();
    EXPECT_NE(fd, -1);
    EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL);
}

TEST(MemoryHeapBase, MemfdUnsealed) {
    auto mHeap = sp<MemoryHeapBase>::make(8192,
                                          MemoryHeapBase::FORCE_MEMFD |
                                          MemoryHeapBase::MEMFD_ALLOW_SEALING,
                                          "Test mapping");
    int fd = mHeap->getHeapID();
    EXPECT_NE(fd, -1);
    EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0);
}

TEST(MemoryHeapBase, MemfdSealedProtected) {
    auto mHeap = sp<MemoryHeapBase>::make(8192,
                                          MemoryHeapBase::FORCE_MEMFD |
                                          MemoryHeapBase::READ_ONLY,
                                          "Test mapping");
    int fd = mHeap->getHeapID();
    EXPECT_NE(fd, -1);
    EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE);
}

TEST(MemoryHeapBase, MemfdUnsealedProtected) {
    auto mHeap = sp<MemoryHeapBase>::make(8192,
                                          MemoryHeapBase::FORCE_MEMFD |
                                          MemoryHeapBase::READ_ONLY |
                                          MemoryHeapBase::MEMFD_ALLOW_SEALING,
                                          "Test mapping");
    int fd = mHeap->getHeapID();
    EXPECT_NE(fd, -1);
    EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE);
}

#else
TEST(MemoryHeapBase, HostMemfdExpected) {
    auto mHeap = sp<MemoryHeapBase>::make(8192,
                                          MemoryHeapBase::READ_ONLY,
                                          "Test mapping");
    int fd = mHeap->getHeapID();
    void* ptr = mHeap->getBase();
    EXPECT_NE(ptr, MAP_FAILED);
    EXPECT_TRUE(ashmem_valid(fd));
    EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
}

TEST(MemoryHeapBase,HostMemfdException) {
    auto mHeap = sp<MemoryHeapBase>::make(8192,
                                          MemoryHeapBase::FORCE_MEMFD |
                                          MemoryHeapBase::READ_ONLY |
                                          MemoryHeapBase::MEMFD_ALLOW_SEALING,
                                          "Test mapping");
    int fd = mHeap->getHeapID();
    void* ptr = mHeap->getBase();
    EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
    EXPECT_TRUE(ashmem_valid(fd));
    EXPECT_NE(ptr, MAP_FAILED);
}

#endif