// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sandbox/linux/services/yama.h" #include <errno.h> #include <fcntl.h> #include <stddef.h> #include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include "base/files/file_util.h" #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/posix/eintr_wrapper.h" #if !defined(PR_SET_PTRACER_ANY) #define PR_SET_PTRACER_ANY ((unsigned long)-1) #endif #if !defined(PR_SET_PTRACER) #define PR_SET_PTRACER 0x59616d61 #endif namespace sandbox { namespace { // Enable or disable the Yama ptracers restrictions. // Return false if Yama is not present on this kernel. bool SetYamaPtracersRestriction(bool enable_restrictions) { unsigned long set_ptracer_arg; if (enable_restrictions) { set_ptracer_arg = 0; } else { set_ptracer_arg = PR_SET_PTRACER_ANY; } const int ret = prctl(PR_SET_PTRACER, set_ptracer_arg); const int prctl_errno = errno; if (0 == ret) { return true; } else { // ENOSYS or EINVAL means Yama is not in the current kernel. CHECK(ENOSYS == prctl_errno || EINVAL == prctl_errno); return false; } } bool CanAccessProcFS() { static const char kProcfsKernelSysPath[] = "/proc/sys/kernel/"; int ret = access(kProcfsKernelSysPath, F_OK); if (ret) { return false; } return true; } } // namespace // static bool Yama::RestrictPtracersToAncestors() { return SetYamaPtracersRestriction(true /* enable_restrictions */); } // static bool Yama::DisableYamaRestrictions() { return SetYamaPtracersRestriction(false /* enable_restrictions */); } // static int Yama::GetStatus() { if (!CanAccessProcFS()) { return 0; } static const char kPtraceScopePath[] = "/proc/sys/kernel/yama/ptrace_scope"; base::ScopedFD yama_scope(HANDLE_EINTR(open(kPtraceScopePath, O_RDONLY))); if (!yama_scope.is_valid()) { const int open_errno = errno; DCHECK(ENOENT == open_errno); // The status is known, yama is not present. return STATUS_KNOWN; } char yama_scope_value = 0; ssize_t num_read = HANDLE_EINTR(read(yama_scope.get(), &yama_scope_value, 1)); PCHECK(1 == num_read); switch (yama_scope_value) { case '0': return STATUS_KNOWN | STATUS_PRESENT; case '1': return STATUS_KNOWN | STATUS_PRESENT | STATUS_ENFORCING; case '2': case '3': return STATUS_KNOWN | STATUS_PRESENT | STATUS_ENFORCING | STATUS_STRICT_ENFORCING; default: NOTREACHED(); return 0; } } // static bool Yama::IsPresent() { return GetStatus() & STATUS_PRESENT; } // static bool Yama::IsEnforcing() { return GetStatus() & STATUS_ENFORCING; } } // namespace sandbox