Home | History | Annotate | Download | only in crash_reporter
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "user_collector.h"
     18 
     19 #include <elf.h>
     20 #include <sys/cdefs.h>  // For __WORDSIZE
     21 #include <unistd.h>
     22 
     23 #include <base/files/file_util.h>
     24 #include <base/files/scoped_temp_dir.h>
     25 #include <base/strings/string_split.h>
     26 #include <brillo/syslog_logging.h>
     27 #include <gmock/gmock.h>
     28 #include <gtest/gtest.h>
     29 
     30 using base::FilePath;
     31 using brillo::FindLog;
     32 
     33 namespace {
     34 
     35 int s_crashes = 0;
     36 bool s_metrics = false;
     37 
     38 const char kFilePath[] = "/my/path";
     39 
     40 void CountCrash() {
     41   ++s_crashes;
     42 }
     43 
     44 bool IsMetrics() {
     45   return s_metrics;
     46 }
     47 
     48 }  // namespace
     49 
     50 class UserCollectorMock : public UserCollector {
     51  public:
     52   MOCK_METHOD0(SetUpDBus, void());
     53 };
     54 
     55 class UserCollectorTest : public ::testing::Test {
     56   void SetUp() {
     57     s_crashes = 0;
     58 
     59     EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
     60 
     61     collector_.Initialize(CountCrash,
     62                           kFilePath,
     63                           IsMetrics,
     64                           false,
     65                           false,
     66                           false,
     67                           "");
     68 
     69     EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
     70 
     71     mkdir(test_dir_.path().Append("test").value().c_str(), 0777);
     72     pid_ = getpid();
     73     brillo::ClearLog();
     74   }
     75 
     76  protected:
     77   void ExpectFileEquals(const char *golden,
     78                         const FilePath &file_path) {
     79     std::string contents;
     80     EXPECT_TRUE(base::ReadFileToString(file_path, &contents));
     81     EXPECT_EQ(golden, contents);
     82   }
     83 
     84   std::vector<std::string> SplitLines(const std::string &lines) const {
     85     return base::SplitString(lines, "\n", base::TRIM_WHITESPACE,
     86                              base::SPLIT_WANT_ALL);
     87   }
     88 
     89   UserCollectorMock collector_;
     90   pid_t pid_;
     91   base::ScopedTempDir test_dir_;
     92 };
     93 
     94 TEST_F(UserCollectorTest, ParseCrashAttributes) {
     95   pid_t pid;
     96   int signal;
     97   uid_t uid;
     98   gid_t gid;
     99   std::string exec_name;
    100   EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:1000:2000:foobar",
    101       &pid, &signal, &uid, &gid, &exec_name));
    102   EXPECT_EQ(123456, pid);
    103   EXPECT_EQ(11, signal);
    104   EXPECT_EQ(1000, uid);
    105   EXPECT_EQ(2000, gid);
    106   EXPECT_EQ("foobar", exec_name);
    107   EXPECT_TRUE(collector_.ParseCrashAttributes("4321:6:barfoo",
    108       &pid, &signal, &uid, &gid, &exec_name));
    109   EXPECT_EQ(4321, pid);
    110   EXPECT_EQ(6, signal);
    111   EXPECT_EQ(-1, uid);
    112   EXPECT_EQ(-1, gid);
    113   EXPECT_EQ("barfoo", exec_name);
    114 
    115   EXPECT_FALSE(collector_.ParseCrashAttributes("123456:11",
    116       &pid, &signal, &uid, &gid, &exec_name));
    117 
    118   EXPECT_TRUE(collector_.ParseCrashAttributes("123456:11:exec:extra",
    119       &pid, &signal, &uid, &gid, &exec_name));
    120   EXPECT_EQ("exec:extra", exec_name);
    121 
    122   EXPECT_FALSE(collector_.ParseCrashAttributes("12345p:11:foobar",
    123       &pid, &signal, &uid, &gid, &exec_name));
    124 
    125   EXPECT_FALSE(collector_.ParseCrashAttributes("123456:1 :foobar",
    126       &pid, &signal, &uid, &gid, &exec_name));
    127 
    128   EXPECT_FALSE(collector_.ParseCrashAttributes("123456::foobar",
    129       &pid, &signal, &uid, &gid, &exec_name));
    130 }
    131 
    132 TEST_F(UserCollectorTest, ShouldDumpDeveloperImageOverridesConsent) {
    133   std::string reason;
    134   EXPECT_TRUE(collector_.ShouldDump(false, true, &reason));
    135   EXPECT_EQ("developer build - not testing - always dumping", reason);
    136 
    137   // When running a crash test, behave as normal.
    138   EXPECT_FALSE(collector_.ShouldDump(false, false, &reason));
    139   EXPECT_EQ("ignoring - no consent", reason);
    140 }
    141 
    142 TEST_F(UserCollectorTest, ShouldDumpUseConsentProductionImage) {
    143   std::string result;
    144   EXPECT_FALSE(collector_.ShouldDump(false, false, &result));
    145   EXPECT_EQ("ignoring - no consent", result);
    146 
    147   EXPECT_TRUE(collector_.ShouldDump(true, false, &result));
    148   EXPECT_EQ("handling", result);
    149 }
    150 
    151 TEST_F(UserCollectorTest, HandleCrashWithoutConsent) {
    152   s_metrics = false;
    153   collector_.HandleCrash("20:10:ignored", "foobar");
    154   EXPECT_TRUE(FindLog(
    155       "Received crash notification for foobar[20] sig 10"));
    156   ASSERT_EQ(s_crashes, 0);
    157 }
    158 
    159 TEST_F(UserCollectorTest, HandleNonChromeCrashWithConsent) {
    160   s_metrics = true;
    161   collector_.HandleCrash("5:2:ignored", "chromeos-wm");
    162   EXPECT_TRUE(FindLog(
    163       "Received crash notification for chromeos-wm[5] sig 2"));
    164   ASSERT_EQ(s_crashes, 1);
    165 }
    166 
    167 TEST_F(UserCollectorTest, GetProcessPath) {
    168   FilePath path = collector_.GetProcessPath(100);
    169   ASSERT_EQ("/proc/100", path.value());
    170 }
    171 
    172 TEST_F(UserCollectorTest, GetSymlinkTarget) {
    173   FilePath result;
    174   ASSERT_FALSE(collector_.GetSymlinkTarget(FilePath("/does_not_exist"),
    175                                            &result));
    176   ASSERT_TRUE(FindLog(
    177       "Readlink failed on /does_not_exist with 2"));
    178   std::string long_link = test_dir_.path().value();
    179   for (int i = 0; i < 50; ++i)
    180     long_link += "0123456789";
    181   long_link += "/gold";
    182 
    183   for (size_t len = 1; len <= long_link.size(); ++len) {
    184     std::string this_link;
    185     static const char* kLink =
    186         test_dir_.path().Append("test/this_link").value().c_str();
    187     this_link.assign(long_link.c_str(), len);
    188     ASSERT_EQ(len, this_link.size());
    189     unlink(kLink);
    190     ASSERT_EQ(0, symlink(this_link.c_str(), kLink));
    191     ASSERT_TRUE(collector_.GetSymlinkTarget(FilePath(kLink), &result));
    192     ASSERT_EQ(this_link, result.value());
    193   }
    194 }
    195 
    196 TEST_F(UserCollectorTest, GetExecutableBaseNameFromPid) {
    197   std::string base_name;
    198   EXPECT_FALSE(collector_.GetExecutableBaseNameFromPid(0, &base_name));
    199   EXPECT_TRUE(FindLog(
    200       "Readlink failed on /proc/0/exe with 2"));
    201   EXPECT_TRUE(FindLog(
    202       "GetSymlinkTarget failed - Path /proc/0 DirectoryExists: 0"));
    203   EXPECT_TRUE(FindLog("stat /proc/0/exe failed: -1 2"));
    204 
    205   brillo::ClearLog();
    206   pid_t my_pid = getpid();
    207   EXPECT_TRUE(collector_.GetExecutableBaseNameFromPid(my_pid, &base_name));
    208   EXPECT_FALSE(FindLog("Readlink failed"));
    209   EXPECT_EQ("crash_reporter_tests", base_name);
    210 }
    211 
    212 TEST_F(UserCollectorTest, GetFirstLineWithPrefix) {
    213   std::vector<std::string> lines;
    214   std::string line;
    215 
    216   EXPECT_FALSE(collector_.GetFirstLineWithPrefix(lines, "Name:", &line));
    217   EXPECT_EQ("", line);
    218 
    219   lines.push_back("Name:\tls");
    220   lines.push_back("State:\tR (running)");
    221   lines.push_back(" Foo:\t1000");
    222 
    223   line.clear();
    224   EXPECT_TRUE(collector_.GetFirstLineWithPrefix(lines, "Name:", &line));
    225   EXPECT_EQ(lines[0], line);
    226 
    227   line.clear();
    228   EXPECT_TRUE(collector_.GetFirstLineWithPrefix(lines, "State:", &line));
    229   EXPECT_EQ(lines[1], line);
    230 
    231   line.clear();
    232   EXPECT_FALSE(collector_.GetFirstLineWithPrefix(lines, "Foo:", &line));
    233   EXPECT_EQ("", line);
    234 
    235   line.clear();
    236   EXPECT_TRUE(collector_.GetFirstLineWithPrefix(lines, " Foo:", &line));
    237   EXPECT_EQ(lines[2], line);
    238 
    239   line.clear();
    240   EXPECT_FALSE(collector_.GetFirstLineWithPrefix(lines, "Bar:", &line));
    241   EXPECT_EQ("", line);
    242 }
    243 
    244 TEST_F(UserCollectorTest, GetIdFromStatus) {
    245   int id = 1;
    246   EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
    247                                           UserCollector::kIdEffective,
    248                                           SplitLines("nothing here"),
    249                                           &id));
    250   EXPECT_EQ(id, 1);
    251 
    252   // Not enough parameters.
    253   EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
    254                                           UserCollector::kIdReal,
    255                                           SplitLines("line 1\nUid:\t1\n"),
    256                                           &id));
    257 
    258   const std::vector<std::string> valid_contents =
    259       SplitLines("\nUid:\t1\t2\t3\t4\nGid:\t5\t6\t7\t8\n");
    260   EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
    261                                          UserCollector::kIdReal,
    262                                          valid_contents,
    263                                          &id));
    264   EXPECT_EQ(1, id);
    265 
    266   EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
    267                                          UserCollector::kIdEffective,
    268                                          valid_contents,
    269                                          &id));
    270   EXPECT_EQ(2, id);
    271 
    272   EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
    273                                          UserCollector::kIdFileSystem,
    274                                          valid_contents,
    275                                          &id));
    276   EXPECT_EQ(4, id);
    277 
    278   EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kGroupId,
    279                                          UserCollector::kIdEffective,
    280                                          valid_contents,
    281                                          &id));
    282   EXPECT_EQ(6, id);
    283 
    284   EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kGroupId,
    285                                          UserCollector::kIdSet,
    286                                          valid_contents,
    287                                          &id));
    288   EXPECT_EQ(7, id);
    289 
    290   EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kGroupId,
    291                                           UserCollector::IdKind(5),
    292                                           valid_contents,
    293                                           &id));
    294   EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kGroupId,
    295                                           UserCollector::IdKind(-1),
    296                                           valid_contents,
    297                                           &id));
    298 
    299   // Fail if junk after number
    300   EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
    301                                           UserCollector::kIdReal,
    302                                           SplitLines("Uid:\t1f\t2\t3\t4\n"),
    303                                           &id));
    304   EXPECT_TRUE(collector_.GetIdFromStatus(UserCollector::kUserId,
    305                                          UserCollector::kIdReal,
    306                                          SplitLines("Uid:\t1\t2\t3\t4\n"),
    307                                          &id));
    308   EXPECT_EQ(1, id);
    309 
    310   // Fail if more than 4 numbers.
    311   EXPECT_FALSE(collector_.GetIdFromStatus(UserCollector::kUserId,
    312                                           UserCollector::kIdReal,
    313                                           SplitLines("Uid:\t1\t2\t3\t4\t5\n"),
    314                                           &id));
    315 }
    316 
    317 TEST_F(UserCollectorTest, GetStateFromStatus) {
    318   std::string state;
    319   EXPECT_FALSE(collector_.GetStateFromStatus(SplitLines("nothing here"),
    320                                              &state));
    321   EXPECT_EQ("", state);
    322 
    323   EXPECT_TRUE(collector_.GetStateFromStatus(SplitLines("State:\tR (running)"),
    324                                             &state));
    325   EXPECT_EQ("R (running)", state);
    326 
    327   EXPECT_TRUE(collector_.GetStateFromStatus(
    328       SplitLines("Name:\tls\nState:\tZ (zombie)\n"), &state));
    329   EXPECT_EQ("Z (zombie)", state);
    330 }
    331 
    332 TEST_F(UserCollectorTest, GetUserInfoFromName) {
    333   gid_t gid = 100;
    334   uid_t uid = 100;
    335   EXPECT_TRUE(collector_.GetUserInfoFromName("root", &uid, &gid));
    336   EXPECT_EQ(0, uid);
    337   EXPECT_EQ(0, gid);
    338 }
    339 
    340 TEST_F(UserCollectorTest, CopyOffProcFilesBadPath) {
    341   // Try a path that is not writable.
    342   ASSERT_FALSE(collector_.CopyOffProcFiles(pid_, FilePath("/bad/path")));
    343   EXPECT_TRUE(FindLog("Could not create /bad/path"));
    344 }
    345 
    346 TEST_F(UserCollectorTest, CopyOffProcFilesBadPid) {
    347   FilePath container_path(test_dir_.path().Append("test/container"));
    348   ASSERT_FALSE(collector_.CopyOffProcFiles(0, container_path));
    349   EXPECT_TRUE(FindLog("Path /proc/0 does not exist"));
    350 }
    351 
    352 TEST_F(UserCollectorTest, CopyOffProcFilesOK) {
    353   FilePath container_path(test_dir_.path().Append("test/container"));
    354   ASSERT_TRUE(collector_.CopyOffProcFiles(pid_, container_path));
    355   EXPECT_FALSE(FindLog("Could not copy"));
    356   static struct {
    357     const char *name;
    358     bool exists;
    359   } expectations[] = {
    360     { "auxv", true },
    361     { "cmdline", true },
    362     { "environ", true },
    363     { "maps", true },
    364     { "mem", false },
    365     { "mounts", false },
    366     { "sched", false },
    367     { "status", true }
    368   };
    369   for (unsigned i = 0; i < sizeof(expectations)/sizeof(expectations[0]); ++i) {
    370     EXPECT_EQ(expectations[i].exists,
    371               base::PathExists(
    372                   container_path.Append(expectations[i].name)));
    373   }
    374 }
    375 
    376 TEST_F(UserCollectorTest, ValidateProcFiles) {
    377   FilePath container_dir = test_dir_.path();
    378 
    379   // maps file not exists (i.e. GetFileSize fails)
    380   EXPECT_FALSE(collector_.ValidateProcFiles(container_dir));
    381 
    382   // maps file is empty
    383   FilePath maps_file = container_dir.Append("maps");
    384   ASSERT_EQ(0, base::WriteFile(maps_file, nullptr, 0));
    385   ASSERT_TRUE(base::PathExists(maps_file));
    386   EXPECT_FALSE(collector_.ValidateProcFiles(container_dir));
    387 
    388   // maps file is not empty
    389   const char data[] = "test data";
    390   ASSERT_EQ(sizeof(data), base::WriteFile(maps_file, data, sizeof(data)));
    391   ASSERT_TRUE(base::PathExists(maps_file));
    392   EXPECT_TRUE(collector_.ValidateProcFiles(container_dir));
    393 }
    394 
    395 TEST_F(UserCollectorTest, ValidateCoreFile) {
    396   FilePath container_dir = test_dir_.path();
    397   FilePath core_file = container_dir.Append("core");
    398 
    399   // Core file does not exist
    400   EXPECT_EQ(UserCollector::kErrorInvalidCoreFile,
    401             collector_.ValidateCoreFile(core_file));
    402   char e_ident[EI_NIDENT];
    403   e_ident[EI_MAG0] = ELFMAG0;
    404   e_ident[EI_MAG1] = ELFMAG1;
    405   e_ident[EI_MAG2] = ELFMAG2;
    406   e_ident[EI_MAG3] = ELFMAG3;
    407 #if __WORDSIZE == 32
    408   e_ident[EI_CLASS] = ELFCLASS32;
    409 #elif __WORDSIZE == 64
    410   e_ident[EI_CLASS] = ELFCLASS64;
    411 #else
    412 #error Unknown/unsupported value of __WORDSIZE.
    413 #endif
    414 
    415   // Core file has the expected header
    416   ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident)));
    417   EXPECT_EQ(UserCollector::kErrorNone,
    418             collector_.ValidateCoreFile(core_file));
    419 
    420 #if __WORDSIZE == 64
    421   // 32-bit core file on 64-bit platform
    422   e_ident[EI_CLASS] = ELFCLASS32;
    423   ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident)));
    424   EXPECT_EQ(UserCollector::kErrorUnsupported32BitCoreFile,
    425             collector_.ValidateCoreFile(core_file));
    426   e_ident[EI_CLASS] = ELFCLASS64;
    427 #endif
    428 
    429   // Invalid core files
    430   ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident) - 1));
    431   EXPECT_EQ(UserCollector::kErrorInvalidCoreFile,
    432             collector_.ValidateCoreFile(core_file));
    433 
    434   e_ident[EI_MAG0] = 0;
    435   ASSERT_TRUE(base::WriteFile(core_file, e_ident, sizeof(e_ident)));
    436   EXPECT_EQ(UserCollector::kErrorInvalidCoreFile,
    437             collector_.ValidateCoreFile(core_file));
    438 }
    439