summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/utility_sandbox_delegate_win.cc
blob: 53d4f0b9937f7c4a3b4e0d3ad6ba6aa67ea3e8a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// 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 "content/browser/utility_sandbox_delegate.h"

#include "base/check.h"
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/sandboxed_process_launcher_delegate.h"
#include "sandbox/policy/features.h"
#include "sandbox/policy/sandbox_type.h"
#include "sandbox/policy/win/sandbox_win.h"
#include "sandbox/win/src/sandbox_policy.h"
#include "sandbox/win/src/sandbox_types.h"

namespace content {
namespace {
// Audio:
//  lockdown_level_(sandbox::USER_LOCKDOWN),
//  initial_level_(sandbox::USER_RESTRICTED_SAME_ACCESS),
//
//  job_level_(sandbox::JOB_LOCKDOWN),
//
//  integrity_level_(sandbox::INTEGRITY_LEVEL_LOW),
//  delayed_integrity_level_(sandbox::INTEGRITY_LEVEL_UNTRUSTED),
bool AudioPreSpawnTarget(sandbox::TargetPolicy* policy) {
  // Audio process privilege requirements:
  //  - Lockdown level of USER_NON_ADMIN
  //  - Delayed integrity level of INTEGRITY_LEVEL_LOW
  //
  // For audio streams to create shared memory regions, lockdown level must be
  // at least USER_LIMITED and delayed integrity level INTEGRITY_LEVEL_LOW,
  // otherwise CreateFileMapping() will fail with error code ERROR_ACCESS_DENIED
  // (0x5).
  //
  // For audio input streams to use ISimpleAudioVolume interface, lockdown
  // level must be set to USER_NON_ADMIN, otherwise
  // WASAPIAudioInputStream::Open() will fail with error code E_ACCESSDENIED
  // (0x80070005) when trying to get a reference to ISimpleAudioVolume
  // interface. See
  // https://cs.chromium.org/chromium/src/media/audio/win/audio_low_latency_input_win.cc
  // Use USER_RESTRICTED_NON_ADMIN over USER_NON_ADMIN to prevent failures when
  // AppLocker and similar application whitelisting solutions are in place.
  policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                        sandbox::USER_RESTRICTED_NON_ADMIN);
  policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);

  // Custom default policy allowing audio drivers to read device properties
  // (https://crbug.com/883326).
  policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
  policy->SetLockdownDefaultDacl();
  policy->SetAlternateDesktop(true);

  return true;
}

// Right now, this policy is essentially unsandboxed, but with default process
// mitigations applied.
// TODO(https://crbug.com/841001) This will be tighted up in future releases.
bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy,
                           const base::CommandLine& cmd_line) {
  sandbox::ResultCode result = policy->SetTokenLevel(sandbox::USER_UNPROTECTED,
                                                     sandbox::USER_UNPROTECTED);
  if (result != sandbox::ResultCode::SBOX_ALL_OK)
    return false;
  result = sandbox::policy::SandboxWin::SetJobLevel(
      cmd_line, sandbox::JOB_UNPROTECTED, 0, policy);
  if (result != sandbox::ResultCode::SBOX_ALL_OK)
    return false;
  return true;
}
}  // namespace

bool UtilitySandboxedProcessLauncherDelegate::GetAppContainerId(
    std::string* appcontainer_id) {
  if ((sandbox_type_ == sandbox::policy::SandboxType::kXrCompositing &&
       base::FeatureList::IsEnabled(sandbox::policy::features::kXRSandbox)) ||
      sandbox_type_ == sandbox::policy::SandboxType::kMediaFoundationCdm) {
    *appcontainer_id = base::WideToUTF8(cmd_line_.GetProgram().value());
    return true;
  }
  return false;
}

bool UtilitySandboxedProcessLauncherDelegate::DisableDefaultPolicy() {
  switch (sandbox_type_) {
    case sandbox::policy::SandboxType::kAudio:
      // Default policy is disabled for audio process to allow audio drivers
      // to read device properties (https://crbug.com/883326).
      return true;
    case sandbox::policy::SandboxType::kNetwork:
      // Default policy is disabled for network process to allow incremental
      // sandbox mitigations to be applied via experiments.
      return true;
    case sandbox::policy::SandboxType::kXrCompositing:
      return base::FeatureList::IsEnabled(
          sandbox::policy::features::kXRSandbox);
    case sandbox::policy::SandboxType::kMediaFoundationCdm:
      // Default policy is disabled for MF Cdm process to allow the application
      // of specific LPAC sandbox policies.
      return true;
    default:
      return false;
  }
}

bool UtilitySandboxedProcessLauncherDelegate::ShouldLaunchElevated() {
  return sandbox_type_ ==
         sandbox::policy::SandboxType::kNoSandboxAndElevatedPrivileges;
}

bool UtilitySandboxedProcessLauncherDelegate::PreSpawnTarget(
    sandbox::TargetPolicy* policy) {
  if (sandbox_type_ == sandbox::policy::SandboxType::kNetwork)
    return NetworkPreSpawnTarget(policy, cmd_line_);

  if (sandbox_type_ == sandbox::policy::SandboxType::kAudio)
    return AudioPreSpawnTarget(policy);

  if (sandbox_type_ == sandbox::policy::SandboxType::kProxyResolver) {
    sandbox::MitigationFlags flags = policy->GetDelayedProcessMitigations();
    flags |= sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
    if (sandbox::SBOX_ALL_OK != policy->SetDelayedProcessMitigations(flags))
      return false;
    return true;
  }

  if (sandbox_type_ == sandbox::policy::SandboxType::kSpeechRecognition) {
    policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
    policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
    policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                          sandbox::USER_LIMITED);
  }

  if (sandbox_type_ == sandbox::policy::SandboxType::kIconReader) {
    policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                          sandbox::USER_LOCKDOWN);
    policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
    policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
    policy->SetLockdownDefaultDacl();
    policy->SetAlternateDesktop(true);

    sandbox::MitigationFlags flags = policy->GetDelayedProcessMitigations();
    flags |= sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
    if (sandbox::SBOX_ALL_OK != policy->SetDelayedProcessMitigations(flags))
      return false;

    // Allow file read. These should match IconLoader::GroupForFilepath().
    policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
                    sandbox::TargetPolicy::FILES_ALLOW_READONLY,
                    L"\\??\\*.exe");
    policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
                    sandbox::TargetPolicy::FILES_ALLOW_READONLY,
                    L"\\??\\*.dll");
    policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
                    sandbox::TargetPolicy::FILES_ALLOW_READONLY,
                    L"\\??\\*.ico");
  }

  if (sandbox_type_ == sandbox::policy::SandboxType::kXrCompositing &&
      base::FeatureList::IsEnabled(sandbox::policy::features::kXRSandbox)) {
    // There were issues with some mitigations, causing an inability
    // to load OpenVR and Oculus APIs.
    // TODO(https://crbug.com/881919): Try to harden the XR Compositor
    // sandbox to use mitigations and restrict the token.
    policy->SetProcessMitigations(0);
    policy->SetDelayedProcessMitigations(0);

    std::string appcontainer_id;
    if (!GetAppContainerId(&appcontainer_id)) {
      return false;
    }
    sandbox::ResultCode result =
        sandbox::policy::SandboxWin::AddAppContainerProfileToPolicy(
            cmd_line_, sandbox_type_, appcontainer_id, policy);
    if (result != sandbox::SBOX_ALL_OK) {
      return false;
    }

    // Unprotected token/job.
    policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
    sandbox::policy::SandboxWin::SetJobLevel(
        cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy);
  }

  if (sandbox_type_ == sandbox::policy::SandboxType::kMediaFoundationCdm) {
    policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
  }

  if (sandbox_type_ == sandbox::policy::SandboxType::kSharingService) {
    auto result =
        sandbox::policy::SandboxWin::AddWin32kLockdownPolicy(policy, false);
    if (result != sandbox::SBOX_ALL_OK)
      return false;

    auto delayed_flags = policy->GetDelayedProcessMitigations();
    delayed_flags |= sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
    result = policy->SetDelayedProcessMitigations(delayed_flags);
    if (result != sandbox::SBOX_ALL_OK)
      return false;
  }

  return true;
}

}  // namespace content