| /* | |
| * Copyright (C) 2020 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 "src/tracing/ipc/memfd.h" | |
| #include <errno.h> | |
| #if PERFETTO_MEMFD_ENABLED() | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <sys/syscall.h> | |
| #include <sys/utsname.h> | |
| #include <unistd.h> | |
| // Some android build bots use a sysroot that doesn't support memfd when | |
| // compiling for the host, so we redefine it if necessary. | |
| #if !defined(__NR_memfd_create) | |
| #if defined(__x86_64__) | |
| #define __NR_memfd_create 319 | |
| #elif defined(__i386__) | |
| #define __NR_memfd_create 356 | |
| #elif defined(__aarch64__) | |
| #define __NR_memfd_create 279 | |
| #elif defined(__arm__) | |
| #define __NR_memfd_create 385 | |
| #else | |
| #error "unsupported sysroot without memfd support" | |
| #endif | |
| #endif // !defined(__NR_memfd_create) | |
| namespace perfetto { | |
| bool HasMemfdSupport() { | |
| static bool kSupportsMemfd = [] { | |
| // Check kernel version supports memfd_create(). Some older kernels segfault | |
| // executing memfd_create() rather than returning ENOSYS (b/116769556). | |
| static constexpr int kRequiredMajor = 3; | |
| static constexpr int kRequiredMinor = 17; | |
| struct utsname uts; | |
| int major, minor; | |
| if (uname(&uts) == 0 && strcmp(uts.sysname, "Linux") == 0 && | |
| sscanf(uts.release, "%d.%d", &major, &minor) == 2 && | |
| ((major < kRequiredMajor || | |
| (major == kRequiredMajor && minor < kRequiredMinor)))) { | |
| return false; | |
| } | |
| base::ScopedFile fd; | |
| fd.reset(static_cast<int>(syscall(__NR_memfd_create, "perfetto_shmem", | |
| MFD_CLOEXEC | MFD_ALLOW_SEALING))); | |
| return !!fd; | |
| }(); | |
| return kSupportsMemfd; | |
| } | |
| base::ScopedFile CreateMemfd(const char* name, unsigned int flags) { | |
| if (!HasMemfdSupport()) { | |
| errno = ENOSYS; | |
| return base::ScopedFile(); | |
| } | |
| return base::ScopedFile( | |
| static_cast<int>(syscall(__NR_memfd_create, name, flags))); | |
| } | |
| } // namespace perfetto | |
| #else // PERFETTO_MEMFD_ENABLED() | |
| namespace perfetto { | |
| bool HasMemfdSupport() { | |
| return false; | |
| } | |
| base::ScopedFile CreateMemfd(const char*, unsigned int) { | |
| errno = ENOSYS; | |
| return base::ScopedFile(); | |
| } | |
| } // namespace perfetto | |
| #endif // PERFETTO_MEMFD_ENABLED() |