1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 <string>
6 #include <vector>
7 
8 #include "base/bind.h"
9 #include "base/run_loop.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "content/browser/utility_process_host.h"
14 #include "content/public/browser/browser_task_traits.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/test/browser_test.h"
17 #include "content/public/test/content_browser_test.h"
18 #include "content/public/test/test_service.mojom.h"
19 #include "content/test/sandbox_status.test-mojom.h"
20 #include "mojo/public/cpp/bindings/remote.h"
21 #include "sandbox/policy/linux/sandbox_linux.h"
22 #include "sandbox/policy/switches.h"
23 
24 using sandbox::policy::SandboxLinux;
25 using sandbox::policy::SandboxType;
26 
27 namespace {
28 
GetSandboxTypesToTest()29 std::vector<SandboxType> GetSandboxTypesToTest() {
30   std::vector<SandboxType> types;
31   // We need the standard sandbox config to run this test.
32   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
33           sandbox::policy::switches::kNoSandbox)) {
34     return types;
35   }
36 
37   for (SandboxType t = SandboxType::kNoSandbox; t <= SandboxType::kMaxValue;
38        t = static_cast<SandboxType>(static_cast<int>(t) + 1)) {
39     // These sandbox types can't be spawned in a utility process.
40     if (t == SandboxType::kRenderer || t == SandboxType::kGpu)
41       continue;
42 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
43     if (t == SandboxType::kZygoteIntermediateSandbox)
44       continue;
45 #endif
46 
47     types.push_back(t);
48   }
49   return types;
50 }
51 
52 }  // namespace
53 
54 namespace content {
55 
56 constexpr char kTestProcessName[] = "sandbox_test_process";
57 
58 class UtilityProcessSandboxBrowserTest
59     : public ContentBrowserTest,
60       public ::testing::WithParamInterface<SandboxType> {
61  public:
62   UtilityProcessSandboxBrowserTest() = default;
63   ~UtilityProcessSandboxBrowserTest() override = default;
64 
65  protected:
RunUtilityProcess()66   void RunUtilityProcess() {
67     DCHECK_CURRENTLY_ON(BrowserThread::UI);
68     base::RunLoop run_loop;
69     done_closure_ =
70         base::BindOnce(&UtilityProcessSandboxBrowserTest::DoneRunning,
71                        base::Unretained(this), run_loop.QuitClosure());
72     GetIOThreadTaskRunner({})->PostTask(
73         FROM_HERE,
74         base::BindOnce(
75             &UtilityProcessSandboxBrowserTest::RunUtilityProcessOnIOThread,
76             base::Unretained(this)));
77     run_loop.Run();
78   }
79 
80  private:
RunUtilityProcessOnIOThread()81   void RunUtilityProcessOnIOThread() {
82     DCHECK_CURRENTLY_ON(BrowserThread::IO);
83     UtilityProcessHost* host = new UtilityProcessHost();
84     host->SetSandboxType(GetParam());
85     host->SetName(base::ASCIIToUTF16("SandboxTestProcess"));
86     host->SetMetricsName(kTestProcessName);
87     EXPECT_TRUE(host->Start());
88 
89     host->GetChildProcess()->BindReceiver(
90         service_.BindNewPipeAndPassReceiver());
91     service_->GetSandboxStatus(base::BindOnce(
92         &UtilityProcessSandboxBrowserTest::OnGotSandboxStatusOnIOThread,
93         base::Unretained(this)));
94   }
95 
OnGotSandboxStatusOnIOThread(int32_t sandbox_status)96   void OnGotSandboxStatusOnIOThread(int32_t sandbox_status) {
97     DCHECK_CURRENTLY_ON(BrowserThread::IO);
98 
99     // Aside from kNoSandbox, every utility process launched explicitly with a
100     // sandbox type should always end up with a sandbox.
101     // kVideoCapture is equivalent to kNoSandbox on all platforms except
102     // Fuchsia.
103     switch (GetParam()) {
104       case SandboxType::kNoSandbox:
105       case SandboxType::kVideoCapture:
106         EXPECT_EQ(sandbox_status, 0);
107         break;
108 
109       case SandboxType::kCdm:
110       case SandboxType::kPpapi:
111       case SandboxType::kPrintCompositor:
112       case SandboxType::kSharingService:
113       case SandboxType::kUtility: {
114         constexpr int kExpectedFullSandboxFlags =
115             SandboxLinux::kPIDNS | SandboxLinux::kNetNS |
116             SandboxLinux::kSeccompBPF | SandboxLinux::kYama |
117             SandboxLinux::kSeccompTSYNC | SandboxLinux::kUserNS;
118         EXPECT_EQ(sandbox_status, kExpectedFullSandboxFlags);
119         break;
120       }
121 
122       case SandboxType::kAudio:
123 #if defined(OS_CHROMEOS)
124       case SandboxType::kIme:
125       case SandboxType::kTts:
126 #endif
127       case SandboxType::kNetwork:
128       case SandboxType::kSpeechRecognition: {
129         constexpr int kExpectedPartialSandboxFlags =
130             SandboxLinux::kSeccompBPF | SandboxLinux::kYama |
131             SandboxLinux::kSeccompTSYNC;
132         EXPECT_EQ(sandbox_status, kExpectedPartialSandboxFlags);
133         break;
134       }
135 
136       case SandboxType::kGpu:
137       case SandboxType::kRenderer:
138       case SandboxType::kZygoteIntermediateSandbox:
139         NOTREACHED();
140         break;
141     }
142 
143     service_.reset();
144     GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(done_closure_));
145   }
146 
DoneRunning(base::OnceClosure quit_closure)147   void DoneRunning(base::OnceClosure quit_closure) {
148     DCHECK_CURRENTLY_ON(BrowserThread::UI);
149     std::move(quit_closure).Run();
150   }
151 
152   mojo::Remote<mojom::SandboxStatusService> service_;
153   base::OnceClosure done_closure_;
154 };
155 
IN_PROC_BROWSER_TEST_P(UtilityProcessSandboxBrowserTest,VerifySandboxType)156 IN_PROC_BROWSER_TEST_P(UtilityProcessSandboxBrowserTest, VerifySandboxType) {
157   RunUtilityProcess();
158 }
159 
160 INSTANTIATE_TEST_SUITE_P(
161     All,
162     UtilityProcessSandboxBrowserTest,
163     testing::ValuesIn(GetSandboxTypesToTest()),
164     [](const testing::TestParamInfo<
__anon88b949390202(const testing::TestParamInfo< UtilityProcessSandboxBrowserTest::ParamType>& info) 165         UtilityProcessSandboxBrowserTest::ParamType>& info) {
166       auto name = sandbox::policy::StringFromUtilitySandboxType(info.param);
167       name[0] = base::ToUpperASCII(name[0]);
168       return name;
169     });
170 
171 }  // namespace content
172