This source file includes following definitions.
- CanPtrace
- ExitZeroIfCanPtrace
- CanSubProcessPtrace
- TEST
- SANDBOX_TEST
- SetYamaRestrictions
- TEST
- DoNothing
- SANDBOX_TEST
#include <errno.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/posix/eintr_wrapper.h"
#include "sandbox/linux/services/scoped_process.h"
#include "sandbox/linux/services/yama.h"
#include "sandbox/linux/tests/unit_tests.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace sandbox {
namespace {
bool CanPtrace(pid_t pid) {
int ret;
ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
if (ret == -1) {
CHECK_EQ(EPERM, errno);
return false;
}
siginfo_t process_info;
int wait_ret = HANDLE_EINTR(waitid(P_PID, pid, &process_info, WSTOPPED));
PCHECK(0 == wait_ret);
PCHECK(0 == ptrace(PTRACE_DETACH, pid, NULL, NULL));
return true;
}
void ExitZeroIfCanPtrace(pid_t pid) {
if (CanPtrace(pid)) {
_exit(0);
} else {
_exit(1);
}
}
bool CanSubProcessPtrace(pid_t pid) {
ScopedProcess process(base::Bind(&ExitZeroIfCanPtrace, pid));
bool signaled;
int exit_code = process.WaitForExit(&signaled);
CHECK(!signaled);
return 0 == exit_code;
}
TEST(Yama, GetStatus) {
int status1 = Yama::GetStatus();
ASSERT_LE(0, status1);
ASSERT_GE(Yama::STATUS_KNOWN | Yama::STATUS_PRESENT | Yama::STATUS_ENFORCING |
Yama::STATUS_STRICT_ENFORCING,
status1);
int status2 = Yama::GetStatus();
EXPECT_EQ(status1, status2);
EXPECT_NE(0, Yama::STATUS_KNOWN & status1);
if (status1 & Yama::STATUS_STRICT_ENFORCING) {
EXPECT_TRUE(status1 & Yama::STATUS_ENFORCING);
}
if (status1 & Yama::STATUS_ENFORCING) {
EXPECT_NE(0, status1 & Yama::STATUS_PRESENT);
}
EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_ENFORCING),
Yama::IsEnforcing());
EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_PRESENT),
Yama::IsPresent());
fprintf(stdout,
"Yama present: %s - enforcing: %s\n",
Yama::IsPresent() ? "Y" : "N",
Yama::IsEnforcing() ? "Y" : "N");
}
SANDBOX_TEST(Yama, RestrictPtraceSucceedsWhenYamaPresent) {
bool restricted = Yama::RestrictPtracersToAncestors();
CHECK_EQ(restricted, Yama::IsPresent());
}
void SetYamaRestrictions(bool enable_restriction) {
if (enable_restriction) {
Yama::RestrictPtracersToAncestors();
} else {
Yama::DisableYamaRestrictions();
}
}
TEST(Yama, RestrictPtraceWorks) {
ScopedProcess process1(base::Bind(&SetYamaRestrictions, true));
ASSERT_TRUE(process1.WaitForClosureToRun());
if (Yama::IsEnforcing()) {
ASSERT_FALSE(CanSubProcessPtrace(process1.GetPid()));
}
if (!(Yama::GetStatus() & Yama::STATUS_STRICT_ENFORCING)) {
ASSERT_TRUE(CanPtrace(process1.GetPid()));
ScopedProcess process2(base::Bind(&SetYamaRestrictions, false));
ASSERT_TRUE(process2.WaitForClosureToRun());
ASSERT_TRUE(CanSubProcessPtrace(process2.GetPid()));
}
}
void DoNothing() {}
SANDBOX_TEST(Yama, RestrictPtraceIsDefault) {
if (!Yama::IsPresent())
return;
CHECK(Yama::DisableYamaRestrictions());
ScopedProcess process1(base::Bind(&DoNothing));
if (Yama::IsEnforcing()) {
CHECK(!CanSubProcessPtrace(process1.GetPid()));
}
}
}
}