blob: 22e0847ff32b8ce293eaf0849631c4df20c7c5cf [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/utility_process_host.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/test_service.mojom.h"
#include "content/test/sandbox_status.test-mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ppapi/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "sandbox/policy/linux/sandbox_linux.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "sandbox/policy/sandbox_type.h"
#include "sandbox/policy/switches.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/ash/components/assistant/buildflags.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
using sandbox::mojom::Sandbox;
using sandbox::policy::SandboxLinux;
namespace {
std::vector<Sandbox> GetSandboxTypesToTest() {
std::vector<Sandbox> types;
// We need the standard sandbox config to run this test.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
sandbox::policy::switches::kNoSandbox)) {
return types;
}
for (Sandbox t = Sandbox::kNoSandbox; t <= Sandbox::kMaxValue;
t = static_cast<Sandbox>(static_cast<int>(t) + 1)) {
// These sandbox types can't be spawned in a utility process.
if (t == Sandbox::kRenderer || t == Sandbox::kGpu)
continue;
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (t == Sandbox::kZygoteIntermediateSandbox)
continue;
#endif
types.push_back(t);
}
return types;
}
} // namespace
namespace content {
constexpr char kTestProcessName[] = "sandbox_test_process";
class UtilityProcessSandboxBrowserTest
: public ContentBrowserTest,
public ::testing::WithParamInterface<Sandbox> {
public:
UtilityProcessSandboxBrowserTest() = default;
~UtilityProcessSandboxBrowserTest() override = default;
protected:
void RunUtilityProcess() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::RunLoop run_loop;
done_closure_ =
base::BindOnce(&UtilityProcessSandboxBrowserTest::DoneRunning,
base::Unretained(this), run_loop.QuitClosure());
UtilityProcessHost* host = new UtilityProcessHost();
host->SetSandboxType(GetParam());
host->SetName(u"SandboxTestProcess");
host->SetMetricsName(kTestProcessName);
EXPECT_TRUE(host->Start());
host->GetChildProcess()->BindReceiver(
service_.BindNewPipeAndPassReceiver());
service_->GetSandboxStatus(
base::BindOnce(&UtilityProcessSandboxBrowserTest::OnGotSandboxStatus,
base::Unretained(this)));
run_loop.Run();
}
private:
void OnGotSandboxStatus(int32_t sandbox_status) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Aside from kNoSandbox, every utility process launched explicitly with a
// sandbox type should always end up with a sandbox.
switch (GetParam()) {
case Sandbox::kNoSandbox:
EXPECT_EQ(sandbox_status, 0);
break;
case Sandbox::kCdm:
#if BUILDFLAG(ENABLE_PLUGINS)
case Sandbox::kPpapi:
#endif
case Sandbox::kPrintCompositor:
case Sandbox::kService:
case Sandbox::kServiceWithJit:
case Sandbox::kUtility: {
constexpr int kExpectedFullSandboxFlags =
SandboxLinux::kPIDNS | SandboxLinux::kNetNS |
SandboxLinux::kSeccompBPF | SandboxLinux::kYama |
SandboxLinux::kSeccompTSYNC | SandboxLinux::kUserNS;
EXPECT_EQ(sandbox_status, kExpectedFullSandboxFlags);
break;
}
case Sandbox::kAudio:
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
case Sandbox::kHardwareVideoDecoding:
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_ASH)
case Sandbox::kIme:
case Sandbox::kTts:
#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
case Sandbox::kLibassistant:
#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
case Sandbox::kNetwork:
#if BUILDFLAG(ENABLE_PRINTING)
case Sandbox::kPrintBackend:
#endif
case Sandbox::kSpeechRecognition: {
constexpr int kExpectedPartialSandboxFlags =
SandboxLinux::kSeccompBPF | SandboxLinux::kYama |
SandboxLinux::kSeccompTSYNC;
EXPECT_EQ(sandbox_status, kExpectedPartialSandboxFlags);
break;
}
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
case Sandbox::kScreenAI:
// TODO(https://crbug.com/1278249): Add test.
break;
#endif
case Sandbox::kGpu:
case Sandbox::kRenderer:
case Sandbox::kZygoteIntermediateSandbox:
NOTREACHED();
break;
}
service_.reset();
GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(done_closure_));
}
void DoneRunning(base::OnceClosure quit_closure) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::move(quit_closure).Run();
}
mojo::Remote<mojom::SandboxStatusService> service_;
base::OnceClosure done_closure_;
};
IN_PROC_BROWSER_TEST_P(UtilityProcessSandboxBrowserTest, VerifySandboxType) {
#if BUILDFLAG(IS_LINUX)
if (GetParam() == Sandbox::kHardwareVideoDecoding) {
// TODO(b/195769334): On Linux, this test fails with
// Sandbox::kHardwareVideoDecoding because the pre-sandbox hook needs Ozone
// which is not available in the utility process that this test starts. We
// need to remove the Ozone dependency and re-enable this test.
GTEST_SKIP();
}
#endif // BUILDFLAG(IS_LINUX)
RunUtilityProcess();
}
INSTANTIATE_TEST_SUITE_P(
All,
UtilityProcessSandboxBrowserTest,
testing::ValuesIn(GetSandboxTypesToTest()),
[](const testing::TestParamInfo<
UtilityProcessSandboxBrowserTest::ParamType>& info) {
auto name = sandbox::policy::StringFromUtilitySandboxType(info.param);
name[0] = base::ToUpperASCII(name[0]);
return name;
});
// In some configurations (e.g. Linux ASAN) GetSandboxTypesToTest() returns an
// empty list. Suppress runtime warnings about unparameterized tests. See
// https://crbug.com/1192206
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UtilityProcessSandboxBrowserTest);
} // namespace content