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

Commit 5eb0dcd9 authored by Atneya Nair's avatar Atneya Nair Committed by Gerrit Code Review
Browse files

Merge "Add explicit memfd support to MemoryHeapBase"

parents 148b13fc 7ade4f4c
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