app_container_base.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // Copyright 2017 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. #include <memory>
  5. #include <windows.h>
  6. #include <accctrl.h>
  7. #include <aclapi.h>
  8. #include <sddl.h>
  9. #include <userenv.h>
  10. #include "base/notreached.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/win/scoped_co_mem.h"
  13. #include "base/win/scoped_handle.h"
  14. #include "base/win/scoped_localalloc.h"
  15. #include "sandbox/win/src/acl.h"
  16. #include "sandbox/win/src/app_container_base.h"
  17. #include "sandbox/win/src/restricted_token_utils.h"
  18. #include "sandbox/win/src/win_utils.h"
  19. namespace sandbox {
  20. namespace {
  21. typedef decltype(::CreateAppContainerProfile) CreateAppContainerProfileFunc;
  22. typedef decltype(::DeriveAppContainerSidFromAppContainerName)
  23. DeriveAppContainerSidFromAppContainerNameFunc;
  24. typedef decltype(::DeleteAppContainerProfile) DeleteAppContainerProfileFunc;
  25. typedef decltype(::GetAppContainerFolderPath) GetAppContainerFolderPathFunc;
  26. typedef decltype(
  27. ::GetAppContainerRegistryLocation) GetAppContainerRegistryLocationFunc;
  28. struct FreeSidDeleter {
  29. inline void operator()(void* ptr) const { ::FreeSid(ptr); }
  30. };
  31. GENERIC_MAPPING GetGenericMappingForType(SecurityObjectType object_type) {
  32. GENERIC_MAPPING generic_mapping = {};
  33. switch (object_type) {
  34. case SecurityObjectType::kFile:
  35. generic_mapping.GenericRead = FILE_GENERIC_READ;
  36. generic_mapping.GenericWrite = FILE_GENERIC_WRITE;
  37. generic_mapping.GenericExecute = FILE_GENERIC_EXECUTE;
  38. generic_mapping.GenericAll = FILE_ALL_ACCESS;
  39. break;
  40. case SecurityObjectType::kRegistry:
  41. generic_mapping.GenericRead = KEY_READ;
  42. generic_mapping.GenericWrite = KEY_WRITE;
  43. generic_mapping.GenericExecute = KEY_EXECUTE;
  44. generic_mapping.GenericAll = KEY_ALL_ACCESS;
  45. break;
  46. default:
  47. NOTREACHED();
  48. break;
  49. }
  50. return generic_mapping;
  51. }
  52. class ScopedImpersonation {
  53. public:
  54. explicit ScopedImpersonation(const base::win::ScopedHandle& token) {
  55. BOOL result = ::ImpersonateLoggedOnUser(token.Get());
  56. DCHECK(result);
  57. }
  58. ~ScopedImpersonation() {
  59. BOOL result = ::RevertToSelf();
  60. DCHECK(result);
  61. }
  62. };
  63. } // namespace
  64. // static
  65. AppContainerBase* AppContainerBase::CreateProfile(const wchar_t* package_name,
  66. const wchar_t* display_name,
  67. const wchar_t* description) {
  68. static auto create_app_container_profile =
  69. reinterpret_cast<CreateAppContainerProfileFunc*>(GetProcAddress(
  70. GetModuleHandle(L"userenv"), "CreateAppContainerProfile"));
  71. if (!create_app_container_profile)
  72. return nullptr;
  73. PSID package_sid_ptr = nullptr;
  74. HRESULT hr = create_app_container_profile(
  75. package_name, display_name, description, nullptr, 0, &package_sid_ptr);
  76. if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
  77. return Open(package_name);
  78. if (FAILED(hr))
  79. return nullptr;
  80. std::unique_ptr<void, FreeSidDeleter> sid_deleter(package_sid_ptr);
  81. auto package_sid = base::win::Sid::FromPSID(package_sid_ptr);
  82. if (!package_sid)
  83. return nullptr;
  84. return new AppContainerBase(*package_sid, AppContainerType::kProfile);
  85. }
  86. // static
  87. AppContainerBase* AppContainerBase::Open(const wchar_t* package_name) {
  88. static auto derive_app_container_sid =
  89. reinterpret_cast<DeriveAppContainerSidFromAppContainerNameFunc*>(
  90. GetProcAddress(GetModuleHandle(L"userenv"),
  91. "DeriveAppContainerSidFromAppContainerName"));
  92. if (!derive_app_container_sid)
  93. return nullptr;
  94. PSID package_sid_ptr = nullptr;
  95. HRESULT hr = derive_app_container_sid(package_name, &package_sid_ptr);
  96. if (FAILED(hr))
  97. return nullptr;
  98. std::unique_ptr<void, FreeSidDeleter> sid_deleter(package_sid_ptr);
  99. auto package_sid = base::win::Sid::FromPSID(package_sid_ptr);
  100. if (!package_sid)
  101. return nullptr;
  102. return new AppContainerBase(*package_sid, AppContainerType::kDerived);
  103. }
  104. // static
  105. AppContainerBase* AppContainerBase::CreateLowbox(const wchar_t* sid) {
  106. auto package_sid = base::win::Sid::FromSddlString(sid);
  107. if (!package_sid)
  108. return nullptr;
  109. return new AppContainerBase(*package_sid, AppContainerType::kLowbox);
  110. }
  111. // static
  112. bool AppContainerBase::Delete(const wchar_t* package_name) {
  113. static auto delete_app_container_profile =
  114. reinterpret_cast<DeleteAppContainerProfileFunc*>(GetProcAddress(
  115. GetModuleHandle(L"userenv"), "DeleteAppContainerProfile"));
  116. if (!delete_app_container_profile)
  117. return false;
  118. return SUCCEEDED(delete_app_container_profile(package_name));
  119. }
  120. AppContainerBase::AppContainerBase(base::win::Sid& package_sid,
  121. AppContainerType type)
  122. : ref_count_(0),
  123. package_sid_(std::move(package_sid)),
  124. enable_low_privilege_app_container_(false),
  125. type_(type) {}
  126. AppContainerBase::~AppContainerBase() {}
  127. void AppContainerBase::AddRef() {
  128. // ref_count starts at 0 for this class so can increase from 0 (once).
  129. CHECK(::InterlockedIncrement(&ref_count_) > 0);
  130. }
  131. void AppContainerBase::Release() {
  132. LONG result = ::InterlockedDecrement(&ref_count_);
  133. CHECK(result >= 0);
  134. if (result == 0) {
  135. delete this;
  136. }
  137. }
  138. bool AppContainerBase::GetRegistryLocation(REGSAM desired_access,
  139. base::win::ScopedHandle* key) {
  140. static GetAppContainerRegistryLocationFunc*
  141. get_app_container_registry_location =
  142. reinterpret_cast<GetAppContainerRegistryLocationFunc*>(GetProcAddress(
  143. GetModuleHandle(L"userenv"), "GetAppContainerRegistryLocation"));
  144. if (!get_app_container_registry_location)
  145. return false;
  146. base::win::ScopedHandle token;
  147. if (BuildLowBoxToken(&token) != SBOX_ALL_OK)
  148. return false;
  149. ScopedImpersonation impersonation(token);
  150. HKEY key_handle;
  151. if (FAILED(get_app_container_registry_location(desired_access, &key_handle)))
  152. return false;
  153. key->Set(key_handle);
  154. return true;
  155. }
  156. bool AppContainerBase::GetFolderPath(base::FilePath* file_path) {
  157. static GetAppContainerFolderPathFunc* get_app_container_folder_path =
  158. reinterpret_cast<GetAppContainerFolderPathFunc*>(GetProcAddress(
  159. GetModuleHandle(L"userenv"), "GetAppContainerFolderPath"));
  160. if (!get_app_container_folder_path)
  161. return false;
  162. auto sddl_str = package_sid_.ToSddlString();
  163. if (!sddl_str)
  164. return false;
  165. base::win::ScopedCoMem<wchar_t> path_str;
  166. if (FAILED(get_app_container_folder_path(sddl_str->c_str(), &path_str)))
  167. return false;
  168. *file_path = base::FilePath(path_str.get());
  169. return true;
  170. }
  171. bool AppContainerBase::GetPipePath(const wchar_t* pipe_name,
  172. base::FilePath* pipe_path) {
  173. auto sddl_str = package_sid_.ToSddlString();
  174. if (!sddl_str)
  175. return false;
  176. *pipe_path = base::FilePath(base::StringPrintf(L"\\\\.\\pipe\\%ls\\%ls",
  177. sddl_str->c_str(), pipe_name));
  178. return true;
  179. }
  180. bool AppContainerBase::AccessCheck(const wchar_t* object_name,
  181. SecurityObjectType object_type,
  182. DWORD desired_access,
  183. DWORD* granted_access,
  184. BOOL* access_status) {
  185. SE_OBJECT_TYPE native_object_type;
  186. switch (object_type) {
  187. case SecurityObjectType::kFile:
  188. native_object_type = SE_FILE_OBJECT;
  189. break;
  190. case SecurityObjectType::kRegistry:
  191. native_object_type = SE_REGISTRY_KEY;
  192. break;
  193. default:
  194. ::SetLastError(ERROR_INVALID_PARAMETER);
  195. return false;
  196. }
  197. GENERIC_MAPPING generic_mapping = GetGenericMappingForType(object_type);
  198. ::MapGenericMask(&desired_access, &generic_mapping);
  199. PSECURITY_DESCRIPTOR sd_ptr = nullptr;
  200. PACL dacl = nullptr;
  201. if (::GetNamedSecurityInfo(
  202. object_name, native_object_type,
  203. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  204. DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
  205. nullptr, nullptr, &dacl, nullptr, &sd_ptr) != ERROR_SUCCESS) {
  206. return false;
  207. }
  208. base::win::ScopedLocalAlloc sd = base::win::TakeLocalAlloc(sd_ptr);
  209. if (enable_low_privilege_app_container_) {
  210. base::win::Sid any_package_sid = *base::win::Sid::FromKnownSid(
  211. base::win::WellKnownSid::kAllApplicationPackages);
  212. // We can't create a LPAC token directly, so modify the DACL to simulate it.
  213. // Set mask for ALL APPLICATION PACKAGE Sid to 0.
  214. for (WORD index = 0; index < dacl->AceCount; ++index) {
  215. PVOID temp_ace;
  216. if (!::GetAce(dacl, index, &temp_ace))
  217. return false;
  218. PACE_HEADER header = static_cast<PACE_HEADER>(temp_ace);
  219. if ((header->AceType != ACCESS_ALLOWED_ACE_TYPE) &&
  220. (header->AceType != ACCESS_DENIED_ACE_TYPE)) {
  221. continue;
  222. }
  223. // Allowed and deny aces have the same underlying structure.
  224. PACCESS_ALLOWED_ACE ace = static_cast<PACCESS_ALLOWED_ACE>(temp_ace);
  225. if (!::IsValidSid(&ace->SidStart)) {
  226. continue;
  227. }
  228. if (any_package_sid.Equal(&ace->SidStart)) {
  229. ace->Mask = 0;
  230. }
  231. }
  232. }
  233. PRIVILEGE_SET priv_set = {};
  234. DWORD priv_set_length = sizeof(PRIVILEGE_SET);
  235. base::win::ScopedHandle token;
  236. if (BuildLowBoxToken(&token) != SBOX_ALL_OK)
  237. return false;
  238. return !!::AccessCheck(sd.get(), token.Get(), desired_access,
  239. &generic_mapping, &priv_set, &priv_set_length,
  240. granted_access, access_status);
  241. }
  242. bool AppContainerBase::AddCapability(const wchar_t* capability_name) {
  243. return AddCapability(base::win::Sid::FromNamedCapability(capability_name),
  244. false);
  245. }
  246. bool AppContainerBase::AddCapability(
  247. base::win::WellKnownCapability capability) {
  248. return AddCapability(base::win::Sid::FromKnownCapability(capability), false);
  249. }
  250. bool AppContainerBase::AddCapabilitySddl(const wchar_t* sddl_sid) {
  251. return AddCapability(base::win::Sid::FromSddlString(sddl_sid), false);
  252. }
  253. bool AppContainerBase::AddCapability(
  254. const absl::optional<base::win::Sid>& capability_sid,
  255. bool impersonation_only) {
  256. if (!capability_sid)
  257. return false;
  258. if (!impersonation_only)
  259. capabilities_.push_back(capability_sid->Clone());
  260. impersonation_capabilities_.push_back(capability_sid->Clone());
  261. return true;
  262. }
  263. bool AppContainerBase::AddImpersonationCapability(
  264. const wchar_t* capability_name) {
  265. return AddCapability(base::win::Sid::FromNamedCapability(capability_name),
  266. true);
  267. }
  268. bool AppContainerBase::AddImpersonationCapability(
  269. base::win::WellKnownCapability capability) {
  270. return AddCapability(base::win::Sid::FromKnownCapability(capability), true);
  271. }
  272. bool AppContainerBase::AddImpersonationCapabilitySddl(const wchar_t* sddl_sid) {
  273. return AddCapability(base::win::Sid::FromSddlString(sddl_sid), true);
  274. }
  275. const std::vector<base::win::Sid>& AppContainerBase::GetCapabilities() {
  276. return capabilities_;
  277. }
  278. const std::vector<base::win::Sid>&
  279. AppContainerBase::GetImpersonationCapabilities() {
  280. return impersonation_capabilities_;
  281. }
  282. const base::win::Sid& AppContainerBase::GetPackageSid() const {
  283. return package_sid_;
  284. }
  285. void AppContainerBase::SetEnableLowPrivilegeAppContainer(bool enable) {
  286. enable_low_privilege_app_container_ = enable;
  287. }
  288. bool AppContainerBase::GetEnableLowPrivilegeAppContainer() {
  289. return enable_low_privilege_app_container_;
  290. }
  291. AppContainerType AppContainerBase::GetAppContainerType() {
  292. return type_;
  293. }
  294. std::unique_ptr<SecurityCapabilities>
  295. AppContainerBase::GetSecurityCapabilities() {
  296. return std::make_unique<SecurityCapabilities>(package_sid_, capabilities_);
  297. }
  298. ResultCode AppContainerBase::BuildLowBoxToken(
  299. base::win::ScopedHandle* token,
  300. base::win::ScopedHandle* lockdown) {
  301. if (type_ == AppContainerType::kLowbox) {
  302. if (CreateLowBoxToken(lockdown->Get(), PRIMARY,
  303. GetSecurityCapabilities().get(),
  304. token) != ERROR_SUCCESS) {
  305. return SBOX_ERROR_CANNOT_CREATE_LOWBOX_TOKEN;
  306. }
  307. if (!ReplacePackageSidInDacl(token->Get(), SecurityObjectType::kKernel,
  308. package_sid_, TOKEN_ALL_ACCESS)) {
  309. return SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL;
  310. }
  311. } else if (CreateLowBoxToken(nullptr, IMPERSONATION,
  312. GetSecurityCapabilities().get(),
  313. token) != ERROR_SUCCESS) {
  314. return SBOX_ERROR_CANNOT_CREATE_LOWBOX_IMPERSONATION_TOKEN;
  315. }
  316. return SBOX_ALL_OK;
  317. }
  318. } // namespace sandbox