• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/win/elevation_util.h"
6 
7 #include <shlobj.h>
8 
9 #include "base/command_line.h"
10 #include "base/functional/callback.h"
11 #include "base/process/process.h"
12 #include "base/process/process_handle.h"
13 #include "base/process/process_iterator.h"
14 #include "base/test/test_timeouts.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/time/time.h"
17 #include "base/win/scoped_com_initializer.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
20 
21 namespace base::win {
22 
23 namespace {
24 
25 constexpr wchar_t kMoreExecutable[] = L"more.com";
26 
IsExplorerRunningAtMediumOrLower()27 bool IsExplorerRunningAtMediumOrLower() {
28   ProcessId explorer_pid = GetExplorerPid();
29   return explorer_pid ? IsProcessRunningAtMediumOrLower(explorer_pid) : false;
30 }
31 
32 }  // namespace
33 
TEST(ElevationUtil,RunDeElevated)34 TEST(ElevationUtil, RunDeElevated) {
35   if (!::IsUserAnAdmin() || !IsExplorerRunningAtMediumOrLower()) {
36     GTEST_SKIP();
37   }
38 
39   Process process = RunDeElevated(CommandLine::FromString(L"more.com"));
40   ASSERT_TRUE(process.IsValid());
41 
42   absl::Cleanup terminate_process = [&] {
43     EXPECT_TRUE(process.Terminate(0, false));
44   };
45 
46   ASSERT_TRUE(IsProcessRunningAtMediumOrLower(process.Pid()));
47 }
48 
49 class ElevationUtilRunDeElevatedNoWaitTest
50     : public ::testing::TestWithParam<RepeatingCallback<HRESULT()>> {};
51 
52 INSTANTIATE_TEST_SUITE_P(ElevationUtilRunDeElevatedNoWaitTestCases,
53                          ElevationUtilRunDeElevatedNoWaitTest,
__anond1858cc50302null54                          ::testing::Values(BindRepeating([] {
55                                              return RunDeElevatedNoWait(
56                                                  CommandLine::FromString(
57                                                      kMoreExecutable));
58                                            }),
__anond1858cc50402null59                                            BindRepeating([] {
60                                              return RunDeElevatedNoWait(
61                                                  kMoreExecutable, {});
62                                            })));
63 
TEST_P(ElevationUtilRunDeElevatedNoWaitTest,TestCases)64 TEST_P(ElevationUtilRunDeElevatedNoWaitTest, TestCases) {
65   if (!::IsUserAnAdmin() || !IsExplorerRunningAtMediumOrLower()) {
66     GTEST_SKIP();
67   }
68 
69   ASSERT_EQ(GetProcessCount(kMoreExecutable, /*filter=*/nullptr), 0)
70       << "This test requires that no instances of the `more` command are "
71          "running.";
72 
73   ScopedCOMInitializer com_initializer(ScopedCOMInitializer::kMTA);
74   ASSERT_TRUE(com_initializer.Succeeded());
75 
76   ASSERT_HRESULT_SUCCEEDED(GetParam().Run());
77 
78   // Wait for the process to start running.
79   int i = 0;
80   for (; i < 5; ++i) {
81     PlatformThread::Sleep(TestTimeouts::tiny_timeout());
82     if (GetProcessCount(kMoreExecutable, /*filter=*/nullptr) == 1) {
83       break;
84     }
85   }
86   ASSERT_LT(i, 5);
87 
88   NamedProcessIterator iter(kMoreExecutable, /*filter=*/nullptr);
89   const ProcessEntry* process_entry = iter.NextProcessEntry();
90   ASSERT_TRUE(process_entry);
91   ASSERT_TRUE(IsProcessRunningAtMediumOrLower(process_entry->pid()));
92 
93   EXPECT_TRUE(Process::Open(process_entry->pid()).Terminate(0, false));
94   ASSERT_FALSE(iter.NextProcessEntry());
95 }
96 
97 }  // namespace base::win
98