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 "sandbox/win/src/startup_information_helper.h"
6 
7 #include <Windows.h>
8 
9 #include <algorithm>
10 #include <vector>
11 
12 #include "base/check.h"
13 #include "base/memory/scoped_refptr.h"
14 #include "base/win/startup_information.h"
15 #include "base/win/windows_version.h"
16 #include "sandbox/win/src/app_container_profile.h"
17 #include "sandbox/win/src/security_capabilities.h"
18 
19 namespace sandbox {
20 using base::win::StartupInformation;
21 
StartupInformationHelper()22 StartupInformationHelper::StartupInformationHelper() {}
~StartupInformationHelper()23 StartupInformationHelper::~StartupInformationHelper() {}
24 
UpdateFlags(DWORD flags)25 void StartupInformationHelper::UpdateFlags(DWORD flags) {
26   startup_info_.startup_info()->dwFlags |= flags;
27 }
28 
SetDesktop(std::wstring desktop)29 void StartupInformationHelper::SetDesktop(std::wstring desktop) {
30   desktop_ = desktop;
31   if (!desktop_.empty()) {
32     startup_info_.startup_info()->lpDesktop =
33         const_cast<wchar_t*>(desktop_.c_str());
34   } else {
35     startup_info_.startup_info()->lpDesktop = nullptr;
36   }
37 }
38 
SetMitigations(MitigationFlags flags)39 void StartupInformationHelper::SetMitigations(MitigationFlags flags) {
40   ConvertProcessMitigationsToPolicy(flags, &mitigations_[0],
41                                     &mitigations_size_);
42 }
43 
SetRestrictChildProcessCreation(bool restrict)44 void StartupInformationHelper::SetRestrictChildProcessCreation(bool restrict) {
45   DCHECK(base::win::GetVersion() >= base::win::Version::WIN10_TH2);
46   restrict_child_process_creation_ = restrict;
47 }
48 
SetStdHandles(HANDLE stdout_handle,HANDLE stderr_handle)49 void StartupInformationHelper::SetStdHandles(HANDLE stdout_handle,
50                                              HANDLE stderr_handle) {
51   stdout_handle_ = stdout_handle;
52   AddInheritedHandle(stdout_handle);
53   stderr_handle_ = stderr_handle;
54   if (stderr_handle != stdout_handle)
55     AddInheritedHandle(stderr_handle);
56 }
57 
AddInheritedHandle(HANDLE handle)58 void StartupInformationHelper::AddInheritedHandle(HANDLE handle) {
59   if (handle != INVALID_HANDLE_VALUE) {
60     auto it = std::find(inherited_handle_list_.begin(),
61                         inherited_handle_list_.end(), handle);
62     if (it == inherited_handle_list_.end())
63       inherited_handle_list_.push_back(handle);
64   }
65 }
66 
SetAppContainerProfile(scoped_refptr<AppContainerProfileBase> profile)67 void StartupInformationHelper::SetAppContainerProfile(
68     scoped_refptr<AppContainerProfileBase> profile) {
69   // Only supported for Windows 8+.
70   DCHECK(base::win::GetVersion() >= base::win::Version::WIN8);
71   // LowPrivilegeAppContainer only supported for Windows 10+
72   DCHECK(!profile->GetEnableLowPrivilegeAppContainer() ||
73          base::win::GetVersion() >= base::win::Version::WIN10_RS1);
74 
75   app_container_profile_ = profile;
76   security_capabilities_ = app_container_profile_->GetSecurityCapabilities();
77 }
78 
AddJobToAssociate(HANDLE job_handle)79 void StartupInformationHelper::AddJobToAssociate(HANDLE job_handle) {
80   job_handle_list_.push_back(job_handle);
81 }
82 
CountAttributes()83 int StartupInformationHelper::CountAttributes() {
84   int attribute_count = 0;
85   if (mitigations_[0] || mitigations_[1])
86     ++attribute_count;
87 
88   if (restrict_child_process_creation_)
89     ++attribute_count;
90 
91   if (!inherited_handle_list_.empty())
92     ++attribute_count;
93 
94   if (app_container_profile_) {
95     ++attribute_count;
96     if (app_container_profile_->GetEnableLowPrivilegeAppContainer())
97       ++attribute_count;
98   }
99 
100   if (!job_handle_list_.empty())
101     ++attribute_count;
102 
103   return attribute_count;
104 }
105 
BuildStartupInformation()106 bool StartupInformationHelper::BuildStartupInformation() {
107   // When adding new attributes, any memory referenced needs to have the
108   // same lifetime as startup_info_. This is why we use members below.
109 
110   auto expected_attributes = CountAttributes();
111   if (!startup_info_.InitializeProcThreadAttributeList(expected_attributes))
112     return false;
113 
114   if (mitigations_[0] || mitigations_[1]) {
115     if (!startup_info_.UpdateProcThreadAttribute(
116             PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations_[0],
117             mitigations_size_)) {
118       return false;
119     }
120     expected_attributes--;
121   }
122 
123   if (restrict_child_process_creation_) {
124     child_process_creation_ = PROCESS_CREATION_CHILD_PROCESS_RESTRICTED;
125     if (!startup_info_.UpdateProcThreadAttribute(
126             PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY,
127             &child_process_creation_, sizeof(child_process_creation_))) {
128       return false;
129     }
130     expected_attributes--;
131   }
132 
133   if (inherited_handle_list_.size()) {
134     if (!startup_info_.UpdateProcThreadAttribute(
135             PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &inherited_handle_list_[0],
136             sizeof(HANDLE) * inherited_handle_list_.size())) {
137       return false;
138     }
139     startup_info_.startup_info()->dwFlags |= STARTF_USESTDHANDLES;
140     startup_info_.startup_info()->hStdInput = INVALID_HANDLE_VALUE;
141     startup_info_.startup_info()->hStdOutput = stdout_handle_;
142     startup_info_.startup_info()->hStdError = stderr_handle_;
143     // Allowing inheritance of handles is only secure now that we
144     // have limited which handles will be inherited.
145     inherit_handles_ = true;
146     expected_attributes--;
147   }
148 
149   if (!job_handle_list_.empty()) {
150     if (!startup_info_.UpdateProcThreadAttribute(
151             PROC_THREAD_ATTRIBUTE_JOB_LIST, &job_handle_list_[0],
152             sizeof(HANDLE) * job_handle_list_.size())) {
153       return false;
154     }
155     expected_attributes--;
156   }
157 
158   if (app_container_profile_) {
159     if (!startup_info_.UpdateProcThreadAttribute(
160             PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
161             security_capabilities_.get(), sizeof(SECURITY_CAPABILITIES))) {
162       return false;
163     }
164     expected_attributes--;
165     if (app_container_profile_->GetEnableLowPrivilegeAppContainer()) {
166       all_applications_package_policy_ =
167           PROCESS_CREATION_ALL_APPLICATION_PACKAGES_OPT_OUT;
168       if (!startup_info_.UpdateProcThreadAttribute(
169               PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY,
170               &all_applications_package_policy_,
171               sizeof(all_applications_package_policy_))) {
172         return false;
173       }
174       expected_attributes--;
175     }
176   }
177 
178   CHECK(expected_attributes == 0);
179   return true;
180 }
181 
182 }  // namespace sandbox
183