0

Adjust Print Compositor sandbox for Windows XPS printing

When printing modifiable content (e.g., HTML documents) on Windows with
XPS instead of GDI, the Print Compositor utility process is requested
to generate an XPS object model for the document.  To do this, the Skia
calls made by the Print Compositor in turn make drawing calls to the
Windows XPS Print API.  These will fail due to access-denied errors
unless the sandbox settings are adjusted for the Print Compositor.

Skia drawing for printing makes many calls into the API which are
context aware.  This requires the ability to open a printing context.
With a regular sandbox, this would require relaxing the token level
to USER_INTERACTIVE, which is very permissive.

Rather than relax the sandbox that much, instead change the approach
to use the Windows Low Privilege App Container.  This maintains a
strong sandbox while enabling access to the necessary system printing
APIs for XPS.  In addition to the obvious lpacPrinting capability, it
also needs the lpacCom capability for XPS library initialization.

This change in Windows sandboxing approach for the Print Compositor is
a complete switch for the Print Compositor, including when printing is
still being done using GDI.

Introduce a separate & temporary control flag around this sandboxing
change, so that it can be easily reverted to the old sandboxing method
should it later be found that there is some unexpected impact to GDI
printing.

Bug: 40100562
Change-Id: Ibb3597987857ac2f0a34c5661839392cbfd98777
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1990336
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Alan Screen <awscreen@chromium.org>
Reviewed-by: Will Harris <wfh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1283432}
This commit is contained in:
Alan Screen
2024-04-05 22:30:45 +00:00
committed by Chromium LUCI CQ
parent 16cbf26db1
commit 353a12d12f
5 changed files with 98 additions and 10 deletions

@ -108,6 +108,7 @@
#if BUILDFLAG(IS_WIN)
#include "printing/printing_utils.h"
#include "sandbox/policy/features.h"
#include "sandbox/policy/switches.h"
#endif
@ -2207,16 +2208,6 @@ class PrintCompositorDocumentDataTypeBrowserTest
PrintBrowserTest::SetUp();
}
// TODO(crbug.com/40100562): Tests that generate XPS currently only succeed
// if the test is run with sandboxing disabled. Remove this once sandboxing
// changes for XPS are applied to the PrintCompositor service.
void SetUpCommandLine(base::CommandLine* command_line) override {
PrintBrowserTest::SetUpCommandLine(command_line);
if (GetParam() == DocumentDataType::kXps) {
command_line->AppendSwitch(sandbox::policy::switches::kNoSandbox);
}
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
@ -2242,6 +2233,41 @@ IN_PROC_BROWSER_TEST_P(PrintCompositorDocumentDataTypeBrowserTest,
EXPECT_THAT(print_preview_observer.last_document_composite_data_type(),
testing::Optional(GetParam()));
}
// Demonstrate that the Print Compositor still works using the legacy sandbox
// method, should the `kPrintCompositorLPAC` flag be disabled.
// TODO(crbug.com/40283514): Remove once LPAC sandboxing has been proven to
// work even for GDI.
class PrintCompositorLegacySandboxBrowserTest : public PrintBrowserTest {
void SetUp() override {
std::vector<base::test::FeatureRef> disabled_features;
disabled_features.push_back(
sandbox::policy::features::kPrintCompositorLPAC);
disabled_features.push_back(features::kUseXpsForPrinting);
scoped_feature_list_.InitWithFeatures(/*enabled_features=*/{},
disabled_features);
PrintBrowserTest::SetUp();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(PrintCompositorLegacySandboxBrowserTest,
WindowDotPrint) {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
TestPrintPreviewObserver print_preview_observer(/*wait_for_loaded=*/true);
content::ExecuteScriptAsync(web_contents->GetPrimaryMainFrame(),
"window.print();");
print_preview_observer.WaitUntilPreviewIsReady();
EXPECT_THAT(print_preview_observer.last_document_composite_data_type(),
testing::Optional(DocumentDataType::kPdf));
}
#endif // BUILDFLAG(IS_WIN)
} // namespace printing

@ -14,6 +14,7 @@
#include "content/public/common/sandboxed_process_launcher_delegate.h"
#include "content/utility/sandbox_delegate_data.mojom.h"
#include "printing/buildflags/buildflags.h"
#include "sandbox/policy/features.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "sandbox/policy/win/sandbox_win.h"
#include "sandbox/win/src/app_container.h"
@ -263,6 +264,15 @@ bool UtilitySandboxedProcessLauncherDelegate::GetAppContainerId(
case sandbox::mojom::Sandbox::kXrCompositing:
*appcontainer_id = UtilityAppContainerId(cmd_line_);
return true;
#if BUILDFLAG(ENABLE_PRINTING)
case sandbox::mojom::Sandbox::kPrintCompositor:
if (base::FeatureList::IsEnabled(
sandbox::policy::features::kPrintCompositorLPAC)) {
*appcontainer_id = UtilityAppContainerId(cmd_line_);
return true;
}
return false;
#endif
default:
return false;
}
@ -286,6 +296,14 @@ bool UtilitySandboxedProcessLauncherDelegate::DisableDefaultPolicy() {
case sandbox::mojom::Sandbox::kOnDeviceModelExecution:
// An LPAC policy is used for on-device model execution.
return true;
#if BUILDFLAG(ENABLE_PRINTING)
case sandbox::mojom::Sandbox::kPrintCompositor:
// Default policy is disabled for Print Compositor to allow the
// application of specific LPAC sandbox policies, when that feature is
// enabled.
return base::FeatureList::IsEnabled(
sandbox::policy::features::kPrintCompositorLPAC);
#endif
case sandbox::mojom::Sandbox::kWindowsSystemProxyResolver:
// Default policy is disabled for Windows System Proxy Resolver process to
// allow the application of specific LPAC sandbox policies.
@ -394,6 +412,19 @@ bool UtilitySandboxedProcessLauncherDelegate::InitializeConfig(
}
#endif
#if BUILDFLAG(ENABLE_PRINTING)
if (sandbox_type_ == sandbox::mojom::Sandbox::kPrintCompositor &&
base::FeatureList::IsEnabled(
sandbox::policy::features::kPrintCompositorLPAC)) {
// LPAC sandbox is enabled, so do not use a restricted token.
auto result = config->SetTokenLevel(sandbox::USER_UNPROTECTED,
sandbox::USER_UNPROTECTED);
if (result != sandbox::SBOX_ALL_OK) {
return false;
}
}
#endif
return GetContentClient()->browser()->PreSpawnChild(
config, sandbox_type_,
ContentBrowserClient::ChildSpawnFlags::kChildSpawnFlagNone);

@ -59,6 +59,11 @@ BASE_FEATURE(kGpuLPAC,
"GpuLPAC",
base::FEATURE_ENABLED_BY_DEFAULT);
// Enables Print Compositor Low Privilege AppContainer.
BASE_FEATURE(kPrintCompositorLPAC,
"PrintCompositorLPAC",
base::FEATURE_ENABLED_BY_DEFAULT);
// Enables Renderer AppContainer
BASE_FEATURE(kRendererAppContainer,
"RendererAppContainer",

@ -29,6 +29,7 @@ SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kNetworkServiceFileAllowlist);
SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kWinSboxDisableExtensionPoints);
SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kGpuAppContainer);
SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kGpuLPAC);
SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kPrintCompositorLPAC);
SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kRendererAppContainer);
SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kWinSboxHighRendererJobMemoryLimits);
SANDBOX_POLICY_EXPORT BASE_DECLARE_FEATURE(kWinSboxNetworkServiceSandboxIsLPAC);

@ -506,6 +506,11 @@ std::wstring GetAppContainerProfileName(const std::string& appcontainer_id,
case Sandbox::kOnDeviceModelExecution:
sandbox_base_name = std::string("cr.sb.odm");
break;
#if BUILDFLAG(ENABLE_PRINTING)
case Sandbox::kPrintCompositor:
sandbox_base_name = std::string("cr.sb.prnc");
break;
#endif
case Sandbox::kWindowsSystemProxyResolver:
sandbox_base_name = std::string("cr.sb.pxy");
break;
@ -540,6 +545,11 @@ ResultCode SetupAppContainerProfile(AppContainer* container,
sandbox_type != Sandbox::kMediaFoundationCdm &&
sandbox_type != Sandbox::kNetwork &&
sandbox_type != Sandbox::kOnDeviceModelExecution &&
#if BUILDFLAG(ENABLE_PRINTING)
!(sandbox_type == Sandbox::kPrintCompositor &&
base::FeatureList::IsEnabled(
sandbox::policy::features::kPrintCompositorLPAC)) &&
#endif
sandbox_type != Sandbox::kWindowsSystemProxyResolver) {
return SBOX_ERROR_UNSUPPORTED;
}
@ -604,6 +614,14 @@ ResultCode SetupAppContainerProfile(AppContainer* container,
container->SetEnableLowPrivilegeAppContainer(true);
}
#if BUILDFLAG(ENABLE_PRINTING)
if (sandbox_type == Sandbox::kPrintCompositor) {
container->AddCapability(kLpacCom);
container->AddCapability(L"lpacPrinting");
container->SetEnableLowPrivilegeAppContainer(true);
}
#endif
if (sandbox_type == Sandbox::kWindowsSystemProxyResolver) {
container->AddCapability(base::win::WellKnownCapability::kInternetClient);
container->AddCapability(kLpacServicesManagement);
@ -917,6 +935,13 @@ bool SandboxWin::IsAppContainerEnabledForSandbox(
return true;
}
#if BUILDFLAG(ENABLE_PRINTING)
if (sandbox_type == Sandbox::kPrintCompositor) {
return base::FeatureList::IsEnabled(
sandbox::policy::features::kPrintCompositorLPAC);
}
#endif
if (sandbox_type == Sandbox::kWindowsSystemProxyResolver)
return true;