| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <stdio.h> |
|
|
| #if defined(__MACH__) |
| #include <mach-o/dyld.h> |
| #elif defined(_WIN32) |
| #include <Windows.h> |
| #include <tchar.h> |
| #endif |
|
|
| #include <algorithm> |
| #include <functional> |
| #include <memory> |
| #include <ostream> |
| #include <string> |
|
|
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "absl/base/internal/strerror.h" |
| #include "absl/base/log_severity.h" |
| #include "absl/flags/internal/program_name.h" |
| #include "absl/log/check.h" |
| #include "absl/log/internal/test_helpers.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/escaping.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/string_view.h" |
|
|
| |
| |
| static volatile bool kReallyDie = false; |
|
|
| namespace { |
| using ::testing::_; |
| using ::testing::Eq; |
| using ::testing::NotNull; |
|
|
| using absl::log_internal::kAbslMinLogLevel; |
|
|
| std::string Base64UnescapeOrDie(absl::string_view data) { |
| std::string decoded; |
| CHECK(absl::Base64Unescape(data, &decoded)); |
| return decoded; |
| } |
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| class FileHasSubstrMatcher final : public ::testing::MatcherInterface<FILE*> { |
| public: |
| explicit FileHasSubstrMatcher(absl::string_view needle) : needle_(needle) {} |
|
|
| bool MatchAndExplain( |
| FILE* fp, ::testing::MatchResultListener* listener) const override { |
| std::string buf( |
| std::max<std::string::size_type>(needle_.size() * 2, 163840000), '\0'); |
| size_t buf_start_offset = 0; |
| size_t buf_data_size = 0; |
| |
|
|
| ::fseek(fp, 0, SEEK_SET); |
| while (true) { |
| |
| while (buf_data_size < buf.size()) { |
| const size_t ret = fread(&buf[buf_data_size], sizeof(char), |
| buf.size() - buf_data_size, fp); |
| if (ret == 0) break; |
| buf_data_size += ret; |
| } |
| if (ferror(fp)) { |
| *listener << "error reading file"; |
| return false; |
| } |
| const absl::string_view haystack(&buf[0], buf_data_size); |
| const auto off = haystack.find(needle_); |
| if (off != haystack.npos) { |
| *listener << "string found at offset " << buf_start_offset + off; |
| return true; |
| } |
| if (feof(fp)) { |
| *listener << "string not found"; |
| return false; |
| } |
| |
| |
| |
| memcpy(&buf[0], &buf[buf_data_size - needle_.size()], needle_.size()); |
| buf_start_offset += buf_data_size - needle_.size(); |
| buf_data_size = needle_.size(); |
| } |
| } |
| void DescribeTo(std::ostream* os) const override { |
| *os << "contains the string \"" << needle_ << "\" (base64(\"" |
| << Base64UnescapeOrDie(needle_) << "\"))"; |
| } |
|
|
| void DescribeNegationTo(std::ostream* os) const override { |
| *os << "does not "; |
| DescribeTo(os); |
| } |
|
|
| private: |
| std::string needle_; |
| }; |
|
|
| class StrippingTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| #ifndef NDEBUG |
| |
| |
| GTEST_SKIP() << "StrippingTests skipped since this build is not optimized"; |
| #elif defined(__EMSCRIPTEN__) |
| |
| |
| GTEST_SKIP() |
| << "StrippingTests skipped since this platform is not optimized"; |
| #endif |
| } |
|
|
| |
| |
| std::unique_ptr<FILE, std::function<void(FILE*)>> OpenTestExecutable() { |
| #if defined(__linux__) |
| std::unique_ptr<FILE, std::function<void(FILE*)>> fp( |
| fopen("/proc/self/exe", "rb"), [](FILE* fp) { fclose(fp); }); |
| if (!fp) { |
| const std::string err = absl::base_internal::StrError(errno); |
| absl::FPrintF(stderr, "Failed to open /proc/self/exe: %s\n", err); |
| } |
| return fp; |
| #elif defined(__Fuchsia__) |
| |
| std::unique_ptr<FILE, std::function<void(FILE*)>> fp( |
| fopen(absl::StrCat("/pkg/bin/", |
| absl::flags_internal::ShortProgramInvocationName()) |
| .c_str(), |
| "rb"), |
| [](FILE* fp) { fclose(fp); }); |
| if (!fp) { |
| const std::string err = absl::base_internal::StrError(errno); |
| absl::FPrintF(stderr, "Failed to open /pkg/bin/<binary name>: %s\n", err); |
| } |
| return fp; |
| #elif defined(__MACH__) |
| uint32_t size = 0; |
| int ret = _NSGetExecutablePath(nullptr, &size); |
| if (ret != -1) { |
| absl::FPrintF(stderr, |
| "Failed to get executable path: " |
| "_NSGetExecutablePath(nullptr) returned %d\n", |
| ret); |
| return nullptr; |
| } |
| std::string path(size, '\0'); |
| ret = _NSGetExecutablePath(&path[0], &size); |
| if (ret != 0) { |
| absl::FPrintF( |
| stderr, |
| "Failed to get executable path: _NSGetExecutablePath(buffer) " |
| "returned %d\n", |
| ret); |
| return nullptr; |
| } |
| std::unique_ptr<FILE, std::function<void(FILE*)>> fp( |
| fopen(path.c_str(), "rb"), [](FILE* fp) { fclose(fp); }); |
| if (!fp) { |
| const std::string err = absl::base_internal::StrError(errno); |
| absl::FPrintF(stderr, "Failed to open executable at %s: %s\n", path, err); |
| } |
| return fp; |
| #elif defined(_WIN32) |
| std::basic_string<TCHAR> path(4096, _T('\0')); |
| while (true) { |
| const uint32_t ret = ::GetModuleFileName(nullptr, &path[0], |
| static_cast<DWORD>(path.size())); |
| if (ret == 0) { |
| absl::FPrintF( |
| stderr, |
| "Failed to get executable path: GetModuleFileName(buffer) " |
| "returned 0\n"); |
| return nullptr; |
| } |
| if (ret < path.size()) break; |
| path.resize(path.size() * 2, _T('\0')); |
| } |
| std::unique_ptr<FILE, std::function<void(FILE*)>> fp( |
| _tfopen(path.c_str(), _T("rb")), [](FILE* fp) { fclose(fp); }); |
| if (!fp) absl::FPrintF(stderr, "Failed to open executable\n"); |
| return fp; |
| #else |
| absl::FPrintF(stderr, |
| "OpenTestExecutable() unimplemented on this platform\n"); |
| return nullptr; |
| #endif |
| } |
|
|
| ::testing::Matcher<FILE*> FileHasSubstr(absl::string_view needle) { |
| return MakeMatcher(new FileHasSubstrMatcher(needle)); |
| } |
| }; |
|
|
| |
| |
| |
| |
| TEST_F(StrippingTest, Control) { |
| constexpr char kEncodedPositiveControl[] = |
| "U3RyaXBwaW5nVGVzdC5Qb3NpdGl2ZUNvbnRyb2w="; |
| const std::string encoded_negative_control = |
| absl::Base64Escape("StrippingTest.NegativeControl"); |
|
|
| |
| |
| EXPECT_THAT(Base64UnescapeOrDie("U3RyaXBwaW5nVGVzdC5Qb3NpdGl2ZUNvbnRyb2w="), |
| Eq("StrippingTest.PositiveControl")); |
|
|
| auto exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
| EXPECT_THAT(exe.get(), FileHasSubstr(kEncodedPositiveControl)); |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(encoded_negative_control))); |
| } |
|
|
| TEST_F(StrippingTest, Literal) { |
| |
| |
| |
| |
| const std::string needle = absl::Base64Escape("StrippingTest.Literal"); |
| LOG(INFO) << "U3RyaXBwaW5nVGVzdC5MaXRlcmFs"; |
| auto exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
| if (absl::LogSeverity::kInfo >= kAbslMinLogLevel) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(needle)); |
| } else { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle))); |
| } |
| } |
|
|
| TEST_F(StrippingTest, LiteralInExpression) { |
| |
| |
| |
| |
| const std::string needle = |
| absl::Base64Escape("StrippingTest.LiteralInExpression"); |
| LOG(INFO) << absl::StrCat("secret: ", |
| "U3RyaXBwaW5nVGVzdC5MaXRlcmFsSW5FeHByZXNzaW9u"); |
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
| if (absl::LogSeverity::kInfo >= kAbslMinLogLevel) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(needle)); |
| } else { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle))); |
| } |
| } |
|
|
| TEST_F(StrippingTest, Fatal) { |
| |
| |
| |
| |
| const std::string needle = absl::Base64Escape("StrippingTest.Fatal"); |
| |
| |
| if (kReallyDie) LOG(FATAL) << "U3RyaXBwaW5nVGVzdC5GYXRhbA=="; |
|
|
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
| if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(needle)); |
| } else { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle))); |
| } |
| } |
|
|
| TEST_F(StrippingTest, DFatal) { |
| |
| |
| |
| |
| const std::string needle = absl::Base64Escape("StrippingTest.DFatal"); |
| |
| |
| if (kReallyDie) LOG(DFATAL) << "U3RyaXBwaW5nVGVzdC5ERmF0YWw="; |
|
|
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
| constexpr bool kExpectPresent = absl::kLogDebugFatal >= kAbslMinLogLevel; |
|
|
| |
| |
| |
| constexpr bool kExpectStripped = kAbslMinLogLevel > absl::LogSeverity::kFatal; |
|
|
| if (kExpectPresent) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(needle)); |
| } else if (kExpectStripped) { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle))); |
| } else { |
| |
| |
| } |
| } |
|
|
| TEST_F(StrippingTest, Level) { |
| const std::string needle = absl::Base64Escape("StrippingTest.Level"); |
| volatile auto severity = absl::LogSeverity::kWarning; |
| |
| |
| LOG(LEVEL(severity)) << "U3RyaXBwaW5nVGVzdC5MZXZlbA=="; |
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
| if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) { |
| |
| |
| EXPECT_THAT(exe.get(), FileHasSubstr(needle)); |
| } else { |
| #if (defined(_MSC_VER) && !defined(__clang__)) || defined(__APPLE__) |
| |
| #else |
| |
| |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle))); |
| #endif |
| } |
| } |
|
|
| TEST_F(StrippingTest, Check) { |
| |
| |
| |
| const std::string var_needle = absl::Base64Escape("StrippingTestCheckVar"); |
| const std::string msg_needle = absl::Base64Escape("StrippingTest.Check"); |
| volatile int U3RyaXBwaW5nVGVzdENoZWNrVmFy = 0xCAFE; |
| |
| |
| |
| if (kReallyDie) { |
| CHECK(U3RyaXBwaW5nVGVzdENoZWNrVmFy != U3RyaXBwaW5nVGVzdENoZWNrVmFy) |
| << "U3RyaXBwaW5nVGVzdC5DaGVjaw=="; |
| } |
|
|
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
| if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(var_needle)); |
| EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle)); |
| } else { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle))); |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle))); |
| } |
| } |
|
|
| TEST_F(StrippingTest, CheckOp) { |
| |
| const std::string var_needle1 = |
| absl::Base64Escape("StrippingTestCheckOpVar1"); |
| const std::string var_needle2 = |
| absl::Base64Escape("StrippingTestCheckOpVar2"); |
| const std::string msg_needle = absl::Base64Escape("StrippingTest.CheckOp"); |
| volatile int U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIx = 0xFEED; |
| volatile int U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIy = 0xCAFE; |
| if (kReallyDie) { |
| CHECK_EQ(U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIx, U3RyaXBwaW5nVGVzdENoZWNrT3BWYXIy) |
| << "U3RyaXBwaW5nVGVzdC5DaGVja09w"; |
| } |
|
|
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
|
|
| if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(var_needle1)); |
| EXPECT_THAT(exe.get(), FileHasSubstr(var_needle2)); |
| EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle)); |
| } else { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle1))); |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle2))); |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle))); |
| } |
| } |
|
|
| TEST_F(StrippingTest, CheckStrOp) { |
| |
| const std::string var_needle1 = |
| absl::Base64Escape("StrippingTestCheckStrOpVar1"); |
| const std::string var_needle2 = |
| absl::Base64Escape("StrippingTestCheckStrOpVar2"); |
| const std::string msg_needle = absl::Base64Escape("StrippingTest.CheckStrOp"); |
| const char *volatile U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIx = "FEED"; |
| const char *volatile U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIy = "CAFE"; |
| if (kReallyDie) { |
| CHECK_STREQ(U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIx, |
| U3RyaXBwaW5nVGVzdENoZWNrU3RyT3BWYXIy) |
| << "U3RyaXBwaW5nVGVzdC5DaGVja1N0ck9w"; |
| } |
|
|
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
|
|
| if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(var_needle1)); |
| EXPECT_THAT(exe.get(), FileHasSubstr(var_needle2)); |
| EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle)); |
| } else { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle1))); |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle2))); |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle))); |
| } |
| } |
|
|
| TEST_F(StrippingTest, CheckOk) { |
| |
| const std::string var_needle = absl::Base64Escape("StrippingTestCheckOkVar1"); |
| const std::string msg_needle = absl::Base64Escape("StrippingTest.CheckOk"); |
| volatile bool x = false; |
| auto U3RyaXBwaW5nVGVzdENoZWNrT2tWYXIx = absl::OkStatus(); |
| if (x) { |
| U3RyaXBwaW5nVGVzdENoZWNrT2tWYXIx = |
| absl::InvalidArgumentError("Stripping this is not my job!"); |
| } |
| if (kReallyDie) { |
| CHECK_OK(U3RyaXBwaW5nVGVzdENoZWNrT2tWYXIx) |
| << "U3RyaXBwaW5nVGVzdC5DaGVja09r"; |
| } |
|
|
| std::unique_ptr<FILE, std::function<void(FILE*)>> exe = OpenTestExecutable(); |
| ASSERT_THAT(exe, NotNull()); |
|
|
| if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) { |
| EXPECT_THAT(exe.get(), FileHasSubstr(var_needle)); |
| EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle)); |
| } else { |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle))); |
| EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle))); |
| } |
| } |
|
|
| } |
|
|