16d46ebefSNico Weber //===-- linux.cpp -----------------------------------------------*- C++ -*-===// 26d46ebefSNico Weber // 36d46ebefSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 46d46ebefSNico Weber // See https://llvm.org/LICENSE.txt for license information. 56d46ebefSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 66d46ebefSNico Weber // 76d46ebefSNico Weber //===----------------------------------------------------------------------===// 86d46ebefSNico Weber 96d46ebefSNico Weber #include "platform.h" 106d46ebefSNico Weber 116d46ebefSNico Weber #if SCUDO_LINUX 126d46ebefSNico Weber 136d46ebefSNico Weber #include "common.h" 146a4c3959SChia-hung Duan #include "internal_defs.h" 156d46ebefSNico Weber #include "linux.h" 166d46ebefSNico Weber #include "mutex.h" 1799d92d18SChristopher Ferris #include "report_linux.h" 186d46ebefSNico Weber #include "string_utils.h" 196d46ebefSNico Weber 206d46ebefSNico Weber #include <errno.h> 216d46ebefSNico Weber #include <fcntl.h> 226d46ebefSNico Weber #include <linux/futex.h> 236d46ebefSNico Weber #include <sched.h> 24cc02d61bSBastian Kersting #include <stdio.h> 256d46ebefSNico Weber #include <stdlib.h> 266d46ebefSNico Weber #include <string.h> 276d46ebefSNico Weber #include <sys/mman.h> 286d46ebefSNico Weber #include <sys/stat.h> 296d46ebefSNico Weber #include <sys/syscall.h> 306d46ebefSNico Weber #include <sys/time.h> 316d46ebefSNico Weber #include <time.h> 326d46ebefSNico Weber #include <unistd.h> 336d46ebefSNico Weber 34016e59bfSAlex Brachet #if SCUDO_ANDROID 356d46ebefSNico Weber #include <sys/prctl.h> 36016e59bfSAlex Brachet // Definitions of prctl arguments to set a vma name in Android kernels. 37016e59bfSAlex Brachet #define ANDROID_PR_SET_VMA 0x53564d41 38016e59bfSAlex Brachet #define ANDROID_PR_SET_VMA_ANON_NAME 0 396d46ebefSNico Weber #endif 406d46ebefSNico Weber 416d46ebefSNico Weber namespace scudo { 426d46ebefSNico Weber 43*4634a480SChristopher Ferris #if !defined(SCUDO_PAGE_SIZE) 44*4634a480SChristopher Ferris // This function is only used when page size is not hard-coded. 456d46ebefSNico Weber uptr getPageSize() { return static_cast<uptr>(sysconf(_SC_PAGESIZE)); } 46*4634a480SChristopher Ferris #endif 476d46ebefSNico Weber 486d46ebefSNico Weber void NORETURN die() { abort(); } 496d46ebefSNico Weber 50f5fffbe2SChia-hung Duan // TODO: Will be deprecated. Use the interfaces in MemMapLinux instead. 516d46ebefSNico Weber void *map(void *Addr, uptr Size, UNUSED const char *Name, uptr Flags, 526d46ebefSNico Weber UNUSED MapPlatformData *Data) { 538095449eSKostya Kortchinsky int MmapFlags = MAP_PRIVATE | MAP_ANONYMOUS; 546d46ebefSNico Weber int MmapProt; 556d46ebefSNico Weber if (Flags & MAP_NOACCESS) { 566d46ebefSNico Weber MmapFlags |= MAP_NORESERVE; 576d46ebefSNico Weber MmapProt = PROT_NONE; 586d46ebefSNico Weber } else { 596d46ebefSNico Weber MmapProt = PROT_READ | PROT_WRITE; 603f71ce85SPeter Collingbourne } 61dfa40840SPeter Collingbourne #if defined(__aarch64__) 62dfa40840SPeter Collingbourne #ifndef PROT_MTE 63dfa40840SPeter Collingbourne #define PROT_MTE 0x20 64dfa40840SPeter Collingbourne #endif 65c299d198SPeter Collingbourne if (Flags & MAP_MEMTAG) 66c299d198SPeter Collingbourne MmapProt |= PROT_MTE; 67c299d198SPeter Collingbourne #endif 6878e70ceeSVitaly Buka if (Addr) 696d46ebefSNico Weber MmapFlags |= MAP_FIXED; 706d46ebefSNico Weber void *P = mmap(Addr, Size, MmapProt, MmapFlags, -1, 0); 716d46ebefSNico Weber if (P == MAP_FAILED) { 726d46ebefSNico Weber if (!(Flags & MAP_ALLOWNOMEM) || errno != ENOMEM) 7399d92d18SChristopher Ferris reportMapError(errno == ENOMEM ? Size : 0); 746d46ebefSNico Weber return nullptr; 756d46ebefSNico Weber } 76016e59bfSAlex Brachet #if SCUDO_ANDROID 773f71ce85SPeter Collingbourne if (Name) 78016e59bfSAlex Brachet prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, P, Size, Name); 79016e59bfSAlex Brachet #endif 806d46ebefSNico Weber return P; 816d46ebefSNico Weber } 826d46ebefSNico Weber 83f5fffbe2SChia-hung Duan // TODO: Will be deprecated. Use the interfaces in MemMapLinux instead. 846d46ebefSNico Weber void unmap(void *Addr, uptr Size, UNUSED uptr Flags, 856d46ebefSNico Weber UNUSED MapPlatformData *Data) { 866d46ebefSNico Weber if (munmap(Addr, Size) != 0) 8799d92d18SChristopher Ferris reportUnmapError(reinterpret_cast<uptr>(Addr), Size); 886d46ebefSNico Weber } 896d46ebefSNico Weber 90f5fffbe2SChia-hung Duan // TODO: Will be deprecated. Use the interfaces in MemMapLinux instead. 913f71ce85SPeter Collingbourne void setMemoryPermission(uptr Addr, uptr Size, uptr Flags, 923f71ce85SPeter Collingbourne UNUSED MapPlatformData *Data) { 933f71ce85SPeter Collingbourne int Prot = (Flags & MAP_NOACCESS) ? PROT_NONE : (PROT_READ | PROT_WRITE); 943f71ce85SPeter Collingbourne if (mprotect(reinterpret_cast<void *>(Addr), Size, Prot) != 0) 9599d92d18SChristopher Ferris reportProtectError(Addr, Size, Prot); 963f71ce85SPeter Collingbourne } 973f71ce85SPeter Collingbourne 98f5fffbe2SChia-hung Duan // TODO: Will be deprecated. Use the interfaces in MemMapLinux instead. 996d46ebefSNico Weber void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, 1006d46ebefSNico Weber UNUSED MapPlatformData *Data) { 1016d46ebefSNico Weber void *Addr = reinterpret_cast<void *>(BaseAddress + Offset); 1024458e8c4SVitaly Buka 1036d46ebefSNico Weber while (madvise(Addr, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) { 1046d46ebefSNico Weber } 1056d46ebefSNico Weber } 1066d46ebefSNico Weber 1076d46ebefSNico Weber // Calling getenv should be fine (c)(tm) at any time. 1086d46ebefSNico Weber const char *getEnv(const char *Name) { return getenv(Name); } 1096d46ebefSNico Weber 1106d46ebefSNico Weber namespace { 1116d46ebefSNico Weber enum State : u32 { Unlocked = 0, Locked = 1, Sleeping = 2 }; 1126d46ebefSNico Weber } 1136d46ebefSNico Weber 1146d46ebefSNico Weber bool HybridMutex::tryLock() { 1153ef766adSChia-hung Duan return atomic_compare_exchange_strong(&M, Unlocked, Locked, 1163ef766adSChia-hung Duan memory_order_acquire) == Unlocked; 1176d46ebefSNico Weber } 1186d46ebefSNico Weber 1196d46ebefSNico Weber // The following is based on https://akkadia.org/drepper/futex.pdf. 1206d46ebefSNico Weber void HybridMutex::lockSlow() { 1213ef766adSChia-hung Duan u32 V = atomic_compare_exchange_strong(&M, Unlocked, Locked, 1223ef766adSChia-hung Duan memory_order_acquire); 1236d46ebefSNico Weber if (V == Unlocked) 1246d46ebefSNico Weber return; 1256d46ebefSNico Weber if (V != Sleeping) 1266d46ebefSNico Weber V = atomic_exchange(&M, Sleeping, memory_order_acquire); 1276d46ebefSNico Weber while (V != Unlocked) { 1286d46ebefSNico Weber syscall(SYS_futex, reinterpret_cast<uptr>(&M), FUTEX_WAIT_PRIVATE, Sleeping, 1296d46ebefSNico Weber nullptr, nullptr, 0); 1306d46ebefSNico Weber V = atomic_exchange(&M, Sleeping, memory_order_acquire); 1316d46ebefSNico Weber } 1326d46ebefSNico Weber } 1336d46ebefSNico Weber 1346d46ebefSNico Weber void HybridMutex::unlock() { 1356d46ebefSNico Weber if (atomic_fetch_sub(&M, 1U, memory_order_release) != Locked) { 1366d46ebefSNico Weber atomic_store(&M, Unlocked, memory_order_release); 1376d46ebefSNico Weber syscall(SYS_futex, reinterpret_cast<uptr>(&M), FUTEX_WAKE_PRIVATE, 1, 1386d46ebefSNico Weber nullptr, nullptr, 0); 1396d46ebefSNico Weber } 1406d46ebefSNico Weber } 1416d46ebefSNico Weber 1426a4c3959SChia-hung Duan void HybridMutex::assertHeldImpl() { 1436a4c3959SChia-hung Duan CHECK(atomic_load(&M, memory_order_acquire) != Unlocked); 1446a4c3959SChia-hung Duan } 1456a4c3959SChia-hung Duan 1466d46ebefSNico Weber u64 getMonotonicTime() { 1476d46ebefSNico Weber timespec TS; 1486d46ebefSNico Weber clock_gettime(CLOCK_MONOTONIC, &TS); 1496d46ebefSNico Weber return static_cast<u64>(TS.tv_sec) * (1000ULL * 1000 * 1000) + 1506d46ebefSNico Weber static_cast<u64>(TS.tv_nsec); 1516d46ebefSNico Weber } 1526d46ebefSNico Weber 15332be3405SChristopher Ferris u64 getMonotonicTimeFast() { 15432be3405SChristopher Ferris #if defined(CLOCK_MONOTONIC_COARSE) 15532be3405SChristopher Ferris timespec TS; 15632be3405SChristopher Ferris clock_gettime(CLOCK_MONOTONIC_COARSE, &TS); 15732be3405SChristopher Ferris return static_cast<u64>(TS.tv_sec) * (1000ULL * 1000 * 1000) + 15832be3405SChristopher Ferris static_cast<u64>(TS.tv_nsec); 15932be3405SChristopher Ferris #else 16032be3405SChristopher Ferris return getMonotonicTime(); 16132be3405SChristopher Ferris #endif 16232be3405SChristopher Ferris } 16332be3405SChristopher Ferris 1646d46ebefSNico Weber u32 getNumberOfCPUs() { 1656d46ebefSNico Weber cpu_set_t CPUs; 166561fa844SKostya Kortchinsky // sched_getaffinity can fail for a variety of legitimate reasons (lack of 167561fa844SKostya Kortchinsky // CAP_SYS_NICE, syscall filtering, etc), in which case we shall return 0. 168561fa844SKostya Kortchinsky if (sched_getaffinity(0, sizeof(cpu_set_t), &CPUs) != 0) 169561fa844SKostya Kortchinsky return 0; 1706d46ebefSNico Weber return static_cast<u32>(CPU_COUNT(&CPUs)); 1716d46ebefSNico Weber } 1726d46ebefSNico Weber 17321d50019SPeter Collingbourne u32 getThreadID() { 17421d50019SPeter Collingbourne #if SCUDO_ANDROID 17521d50019SPeter Collingbourne return static_cast<u32>(gettid()); 17621d50019SPeter Collingbourne #else 17721d50019SPeter Collingbourne return static_cast<u32>(syscall(SYS_gettid)); 17821d50019SPeter Collingbourne #endif 17921d50019SPeter Collingbourne } 18021d50019SPeter Collingbourne 1816d46ebefSNico Weber // Blocking is possibly unused if the getrandom block is not compiled in. 1826d46ebefSNico Weber bool getRandom(void *Buffer, uptr Length, UNUSED bool Blocking) { 1836d46ebefSNico Weber if (!Buffer || !Length || Length > MaxRandomLength) 1846d46ebefSNico Weber return false; 1856d46ebefSNico Weber ssize_t ReadBytes; 1866d46ebefSNico Weber #if defined(SYS_getrandom) 1876d46ebefSNico Weber #if !defined(GRND_NONBLOCK) 1886d46ebefSNico Weber #define GRND_NONBLOCK 1 1896d46ebefSNico Weber #endif 1906d46ebefSNico Weber // Up to 256 bytes, getrandom will not be interrupted. 1916d46ebefSNico Weber ReadBytes = 1926d46ebefSNico Weber syscall(SYS_getrandom, Buffer, Length, Blocking ? 0 : GRND_NONBLOCK); 1936d46ebefSNico Weber if (ReadBytes == static_cast<ssize_t>(Length)) 1946d46ebefSNico Weber return true; 1956d46ebefSNico Weber #endif // defined(SYS_getrandom) 1966d46ebefSNico Weber // Up to 256 bytes, a read off /dev/urandom will not be interrupted. 1976d46ebefSNico Weber // Blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. 1986d46ebefSNico Weber const int FileDesc = open("/dev/urandom", O_RDONLY); 1996d46ebefSNico Weber if (FileDesc == -1) 2006d46ebefSNico Weber return false; 2016d46ebefSNico Weber ReadBytes = read(FileDesc, Buffer, Length); 2026d46ebefSNico Weber close(FileDesc); 2036d46ebefSNico Weber return (ReadBytes == static_cast<ssize_t>(Length)); 2046d46ebefSNico Weber } 2056d46ebefSNico Weber 206a1f6ff26SKostya Kortchinsky // Allocation free syslog-like API. 207a1f6ff26SKostya Kortchinsky extern "C" WEAK int async_safe_write_log(int pri, const char *tag, 208a1f6ff26SKostya Kortchinsky const char *msg); 209a1f6ff26SKostya Kortchinsky 2106d46ebefSNico Weber void outputRaw(const char *Buffer) { 211a1f6ff26SKostya Kortchinsky if (&async_safe_write_log) { 212a1f6ff26SKostya Kortchinsky constexpr s32 AndroidLogInfo = 4; 21315754accSKostya Kortchinsky constexpr uptr MaxLength = 1024U; 21415754accSKostya Kortchinsky char LocalBuffer[MaxLength]; 21515754accSKostya Kortchinsky while (strlen(Buffer) > MaxLength) { 21615754accSKostya Kortchinsky uptr P; 21715754accSKostya Kortchinsky for (P = MaxLength - 1; P > 0; P--) { 21815754accSKostya Kortchinsky if (Buffer[P] == '\n') { 21915754accSKostya Kortchinsky memcpy(LocalBuffer, Buffer, P); 22015754accSKostya Kortchinsky LocalBuffer[P] = '\0'; 22115754accSKostya Kortchinsky async_safe_write_log(AndroidLogInfo, "scudo", LocalBuffer); 22215754accSKostya Kortchinsky Buffer = &Buffer[P + 1]; 22315754accSKostya Kortchinsky break; 22415754accSKostya Kortchinsky } 22515754accSKostya Kortchinsky } 22615754accSKostya Kortchinsky // If no newline was found, just log the buffer. 22715754accSKostya Kortchinsky if (P == 0) 22815754accSKostya Kortchinsky break; 22915754accSKostya Kortchinsky } 230a1f6ff26SKostya Kortchinsky async_safe_write_log(AndroidLogInfo, "scudo", Buffer); 231a1f6ff26SKostya Kortchinsky } else { 2321ef0e94dSFangrui Song (void)write(2, Buffer, strlen(Buffer)); 2336d46ebefSNico Weber } 234a1f6ff26SKostya Kortchinsky } 2356d46ebefSNico Weber 2366d46ebefSNico Weber extern "C" WEAK void android_set_abort_message(const char *); 2376d46ebefSNico Weber 2386d46ebefSNico Weber void setAbortMessage(const char *Message) { 2396d46ebefSNico Weber if (&android_set_abort_message) 2406d46ebefSNico Weber android_set_abort_message(Message); 2416d46ebefSNico Weber } 2426d46ebefSNico Weber 2436d46ebefSNico Weber } // namespace scudo 2446d46ebefSNico Weber 2456d46ebefSNico Weber #endif // SCUDO_LINUX 246