124923214SSchrodinger ZHU Yifan //===-- Unittests for mlock -----------------------------------------------===// 224923214SSchrodinger ZHU Yifan // 324923214SSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 424923214SSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information. 524923214SSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 624923214SSchrodinger ZHU Yifan // 724923214SSchrodinger ZHU Yifan //===----------------------------------------------------------------------===// 824923214SSchrodinger ZHU Yifan 924923214SSchrodinger ZHU Yifan #include "src/__support/OSUtil/syscall.h" // For internal syscall function. 1024923214SSchrodinger ZHU Yifan #include "src/errno/libc_errno.h" 1124923214SSchrodinger ZHU Yifan #include "src/sys/mman/madvise.h" 1224923214SSchrodinger ZHU Yifan #include "src/sys/mman/mincore.h" 1324923214SSchrodinger ZHU Yifan #include "src/sys/mman/mlock.h" 1424923214SSchrodinger ZHU Yifan #include "src/sys/mman/mlock2.h" 1524923214SSchrodinger ZHU Yifan #include "src/sys/mman/mlockall.h" 1624923214SSchrodinger ZHU Yifan #include "src/sys/mman/mmap.h" 1724923214SSchrodinger ZHU Yifan #include "src/sys/mman/munlock.h" 1824923214SSchrodinger ZHU Yifan #include "src/sys/mman/munlockall.h" 1924923214SSchrodinger ZHU Yifan #include "src/sys/mman/munmap.h" 2024923214SSchrodinger ZHU Yifan #include "src/sys/resource/getrlimit.h" 2124923214SSchrodinger ZHU Yifan #include "src/unistd/sysconf.h" 2224923214SSchrodinger ZHU Yifan #include "test/UnitTest/ErrnoSetterMatcher.h" 2324923214SSchrodinger ZHU Yifan #include "test/UnitTest/Test.h" 2424923214SSchrodinger ZHU Yifan 2524923214SSchrodinger ZHU Yifan #include <linux/capability.h> 2624923214SSchrodinger ZHU Yifan #include <sys/mman.h> 2724923214SSchrodinger ZHU Yifan #include <sys/resource.h> 2824923214SSchrodinger ZHU Yifan #include <sys/syscall.h> 2924923214SSchrodinger ZHU Yifan #include <unistd.h> 3024923214SSchrodinger ZHU Yifan 3124923214SSchrodinger ZHU Yifan using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; 3224923214SSchrodinger ZHU Yifan 3324923214SSchrodinger ZHU Yifan struct PageHolder { 3424923214SSchrodinger ZHU Yifan size_t size; 3524923214SSchrodinger ZHU Yifan void *addr; 3624923214SSchrodinger ZHU Yifan 3724923214SSchrodinger ZHU Yifan PageHolder() 3824923214SSchrodinger ZHU Yifan : size(LIBC_NAMESPACE::sysconf(_SC_PAGESIZE)), 3924923214SSchrodinger ZHU Yifan addr(LIBC_NAMESPACE::mmap(nullptr, size, PROT_READ | PROT_WRITE, 4024923214SSchrodinger ZHU Yifan MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) {} 4124923214SSchrodinger ZHU Yifan ~PageHolder() { 4224923214SSchrodinger ZHU Yifan if (addr != MAP_FAILED) 4324923214SSchrodinger ZHU Yifan LIBC_NAMESPACE::munmap(addr, size); 4424923214SSchrodinger ZHU Yifan } 4524923214SSchrodinger ZHU Yifan 4624923214SSchrodinger ZHU Yifan char &operator[](size_t i) { return reinterpret_cast<char *>(addr)[i]; } 4724923214SSchrodinger ZHU Yifan 4824923214SSchrodinger ZHU Yifan bool is_valid() { return addr != MAP_FAILED; } 4924923214SSchrodinger ZHU Yifan }; 5024923214SSchrodinger ZHU Yifan 5124923214SSchrodinger ZHU Yifan static bool get_capacity(unsigned int cap) { 5224923214SSchrodinger ZHU Yifan __user_cap_header_struct header; 5324923214SSchrodinger ZHU Yifan header.pid = 0; 5424923214SSchrodinger ZHU Yifan header.version = _LINUX_CAPABILITY_VERSION_3; 5524923214SSchrodinger ZHU Yifan __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; 5624923214SSchrodinger ZHU Yifan // TODO: use capget wrapper once implemented. 5724923214SSchrodinger ZHU Yifan // https://github.com/llvm/llvm-project/issues/80037 5824923214SSchrodinger ZHU Yifan long res = LIBC_NAMESPACE::syscall_impl( 5924923214SSchrodinger ZHU Yifan SYS_capget, LIBC_NAMESPACE::cpp::bit_cast<long>(&header), 6024923214SSchrodinger ZHU Yifan LIBC_NAMESPACE::cpp::bit_cast<long>(&data)); 6124923214SSchrodinger ZHU Yifan if (res < 0) 6224923214SSchrodinger ZHU Yifan return false; 6324923214SSchrodinger ZHU Yifan unsigned idx = CAP_TO_INDEX(cap); 6424923214SSchrodinger ZHU Yifan unsigned shift = CAP_TO_MASK(cap); 6524923214SSchrodinger ZHU Yifan return (data[idx].effective & shift) != 0; 6624923214SSchrodinger ZHU Yifan } 6724923214SSchrodinger ZHU Yifan 6824923214SSchrodinger ZHU Yifan static bool is_permitted_size(size_t size) { 6924923214SSchrodinger ZHU Yifan rlimit rlimits; 7024923214SSchrodinger ZHU Yifan LIBC_NAMESPACE::getrlimit(RLIMIT_MEMLOCK, &rlimits); 7124923214SSchrodinger ZHU Yifan return size <= static_cast<size_t>(rlimits.rlim_cur) || 7224923214SSchrodinger ZHU Yifan get_capacity(CAP_IPC_LOCK); 7324923214SSchrodinger ZHU Yifan } 7424923214SSchrodinger ZHU Yifan 7524923214SSchrodinger ZHU Yifan TEST(LlvmLibcMlockTest, UnMappedMemory) { 7624923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mlock(nullptr, 1024), Fails(ENOMEM)); 7724923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::munlock(nullptr, 1024), Fails(ENOMEM)); 7824923214SSchrodinger ZHU Yifan } 7924923214SSchrodinger ZHU Yifan 8024923214SSchrodinger ZHU Yifan TEST(LlvmLibcMlockTest, Overflow) { 8124923214SSchrodinger ZHU Yifan PageHolder holder; 8224923214SSchrodinger ZHU Yifan EXPECT_TRUE(holder.is_valid()); 8324923214SSchrodinger ZHU Yifan size_t negative_size = -holder.size; 8424923214SSchrodinger ZHU Yifan int expected_errno = is_permitted_size(negative_size) ? EINVAL : ENOMEM; 8524923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mlock(holder.addr, negative_size), 8624923214SSchrodinger ZHU Yifan Fails(expected_errno)); 8724923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::munlock(holder.addr, negative_size), 8824923214SSchrodinger ZHU Yifan Fails(EINVAL)); 8924923214SSchrodinger ZHU Yifan } 9024923214SSchrodinger ZHU Yifan 9124923214SSchrodinger ZHU Yifan #ifdef SYS_mlock2 9224923214SSchrodinger ZHU Yifan TEST(LlvmLibcMlockTest, MLock2) { 9324923214SSchrodinger ZHU Yifan PageHolder holder; 9424923214SSchrodinger ZHU Yifan EXPECT_TRUE(holder.is_valid()); 9524923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::madvise(holder.addr, holder.size, MADV_DONTNEED), 9624923214SSchrodinger ZHU Yifan Succeeds()); 9724923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mlock2(holder.addr, holder.size, 0), Succeeds()); 9824923214SSchrodinger ZHU Yifan unsigned char vec; 9924923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec), 10024923214SSchrodinger ZHU Yifan Succeeds()); 10124923214SSchrodinger ZHU Yifan EXPECT_EQ(vec & 1, 1); 10224923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::munlock(holder.addr, holder.size), Succeeds()); 10324923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::madvise(holder.addr, holder.size, MADV_DONTNEED), 10424923214SSchrodinger ZHU Yifan Succeeds()); 10524923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mlock2(holder.addr, holder.size, MLOCK_ONFAULT), 10624923214SSchrodinger ZHU Yifan Succeeds()); 10724923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec), 10824923214SSchrodinger ZHU Yifan Succeeds()); 10924923214SSchrodinger ZHU Yifan EXPECT_EQ(vec & 1, 0); 11024923214SSchrodinger ZHU Yifan holder[0] = 1; 11124923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec), 11224923214SSchrodinger ZHU Yifan Succeeds()); 11324923214SSchrodinger ZHU Yifan EXPECT_EQ(vec & 1, 1); 11424923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::munlock(holder.addr, holder.size), Succeeds()); 11524923214SSchrodinger ZHU Yifan } 11624923214SSchrodinger ZHU Yifan #endif 11724923214SSchrodinger ZHU Yifan 11824923214SSchrodinger ZHU Yifan TEST(LlvmLibcMlockTest, InvalidFlag) { 11924923214SSchrodinger ZHU Yifan size_t alloc_size = 128; // page size 120*3eb1e6d8Smichaelrj-google LIBC_NAMESPACE::libc_errno = 0; 12124923214SSchrodinger ZHU Yifan void *addr = LIBC_NAMESPACE::mmap(nullptr, alloc_size, PROT_READ, 12224923214SSchrodinger ZHU Yifan MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 12328699e38Slntue ASSERT_ERRNO_SUCCESS(); 12424923214SSchrodinger ZHU Yifan EXPECT_NE(addr, MAP_FAILED); 12524923214SSchrodinger ZHU Yifan 12624923214SSchrodinger ZHU Yifan // Invalid mlock2 flags. 12724923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mlock2(addr, alloc_size, 1234), Fails(EINVAL)); 12824923214SSchrodinger ZHU Yifan 12924923214SSchrodinger ZHU Yifan // Invalid mlockall flags. 13024923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mlockall(1234), Fails(EINVAL)); 13116c15b5fSNick Desaulniers 13216c15b5fSNick Desaulniers // man 2 mlockall says EINVAL is a valid return code when MCL_ONFAULT was 13316c15b5fSNick Desaulniers // specified without MCL_FUTURE or MCL_CURRENT, but this seems to fail on 13416c15b5fSNick Desaulniers // Linux 4.19.y (EOL). 13516c15b5fSNick Desaulniers // TODO(ndesaulniers) re-enable after 13616c15b5fSNick Desaulniers // https://github.com/llvm/llvm-project/issues/80073 is fixed. 13716c15b5fSNick Desaulniers // EXPECT_THAT(LIBC_NAMESPACE::mlockall(MCL_ONFAULT), Fails(EINVAL)); 13824923214SSchrodinger ZHU Yifan 13924923214SSchrodinger ZHU Yifan LIBC_NAMESPACE::munmap(addr, alloc_size); 14024923214SSchrodinger ZHU Yifan } 14124923214SSchrodinger ZHU Yifan 14224923214SSchrodinger ZHU Yifan TEST(LlvmLibcMlockTest, MLockAll) { 14324923214SSchrodinger ZHU Yifan { 14424923214SSchrodinger ZHU Yifan PageHolder holder; 14524923214SSchrodinger ZHU Yifan EXPECT_TRUE(holder.is_valid()); 14624923214SSchrodinger ZHU Yifan EXPECT_THAT( 14724923214SSchrodinger ZHU Yifan LIBC_NAMESPACE::madvise(holder.addr, holder.size, MADV_DONTNEED), 14824923214SSchrodinger ZHU Yifan Succeeds()); 14924923214SSchrodinger ZHU Yifan auto retval = LIBC_NAMESPACE::mlockall(MCL_CURRENT); 15024923214SSchrodinger ZHU Yifan if (retval == -1) { 151*3eb1e6d8Smichaelrj-google EXPECT_TRUE(LIBC_NAMESPACE::libc_errno == ENOMEM || 152*3eb1e6d8Smichaelrj-google LIBC_NAMESPACE::libc_errno == EPERM); 153*3eb1e6d8Smichaelrj-google LIBC_NAMESPACE::libc_errno = 0; 15424923214SSchrodinger ZHU Yifan return; 15524923214SSchrodinger ZHU Yifan } 15624923214SSchrodinger ZHU Yifan unsigned char vec; 15724923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec), 15824923214SSchrodinger ZHU Yifan Succeeds()); 15924923214SSchrodinger ZHU Yifan EXPECT_EQ(vec & 1, 1); 16024923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::munlockall(), Succeeds()); 16124923214SSchrodinger ZHU Yifan } 16224923214SSchrodinger ZHU Yifan { 16324923214SSchrodinger ZHU Yifan auto retval = LIBC_NAMESPACE::mlockall(MCL_FUTURE); 16424923214SSchrodinger ZHU Yifan if (retval == -1) { 165*3eb1e6d8Smichaelrj-google EXPECT_TRUE(LIBC_NAMESPACE::libc_errno == ENOMEM || 166*3eb1e6d8Smichaelrj-google LIBC_NAMESPACE::libc_errno == EPERM); 167*3eb1e6d8Smichaelrj-google LIBC_NAMESPACE::libc_errno = 0; 16824923214SSchrodinger ZHU Yifan return; 16924923214SSchrodinger ZHU Yifan } 17024923214SSchrodinger ZHU Yifan PageHolder holder; 17124923214SSchrodinger ZHU Yifan EXPECT_TRUE(holder.is_valid()); 17224923214SSchrodinger ZHU Yifan unsigned char vec; 17324923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec), 17424923214SSchrodinger ZHU Yifan Succeeds()); 17524923214SSchrodinger ZHU Yifan EXPECT_EQ(vec & 1, 1); 17624923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::munlockall(), Succeeds()); 17724923214SSchrodinger ZHU Yifan } 17824923214SSchrodinger ZHU Yifan #ifdef MCL_ONFAULT 17924923214SSchrodinger ZHU Yifan { 18024923214SSchrodinger ZHU Yifan auto retval = LIBC_NAMESPACE::mlockall(MCL_FUTURE | MCL_ONFAULT); 18124923214SSchrodinger ZHU Yifan if (retval == -1) { 182*3eb1e6d8Smichaelrj-google EXPECT_TRUE(LIBC_NAMESPACE::libc_errno == ENOMEM || 183*3eb1e6d8Smichaelrj-google LIBC_NAMESPACE::libc_errno == EPERM); 184*3eb1e6d8Smichaelrj-google LIBC_NAMESPACE::libc_errno = 0; 18524923214SSchrodinger ZHU Yifan return; 18624923214SSchrodinger ZHU Yifan } 18724923214SSchrodinger ZHU Yifan PageHolder holder; 18824923214SSchrodinger ZHU Yifan EXPECT_TRUE(holder.is_valid()); 18924923214SSchrodinger ZHU Yifan unsigned char vec; 19024923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec), 19124923214SSchrodinger ZHU Yifan Succeeds()); 19224923214SSchrodinger ZHU Yifan EXPECT_EQ(vec & 1, 0); 19324923214SSchrodinger ZHU Yifan holder[0] = 1; 19424923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec), 19524923214SSchrodinger ZHU Yifan Succeeds()); 19624923214SSchrodinger ZHU Yifan EXPECT_EQ(vec & 1, 1); 19724923214SSchrodinger ZHU Yifan EXPECT_THAT(LIBC_NAMESPACE::munlockall(), Succeeds()); 19824923214SSchrodinger ZHU Yifan } 19924923214SSchrodinger ZHU Yifan #endif 20024923214SSchrodinger ZHU Yifan } 201