elevator.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright 2018 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 "chrome/elevation_service/elevator.h"
  5. #include <dpapi.h>
  6. #include <oleauto.h>
  7. #include <stdint.h>
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/files/file_path.h"
  11. #include "base/logging.h"
  12. #include "base/numerics/safe_conversions.h"
  13. #include "base/process/process.h"
  14. #include "base/win/scoped_localalloc.h"
  15. #include "base/win/win_util.h"
  16. #include "chrome/elevation_service/caller_validation.h"
  17. #include "chrome/elevation_service/elevated_recovery_impl.h"
  18. namespace elevation_service {
  19. namespace {
  20. // Returns a base::Process of the process making the RPC call to us, or invalid
  21. // base::Process if could not be determined.
  22. base::Process GetCallingProcess() {
  23. // Validation should always be done impersonating the caller.
  24. HANDLE calling_process_handle;
  25. RPC_STATUS status = I_RpcOpenClientProcess(
  26. nullptr, PROCESS_QUERY_LIMITED_INFORMATION, &calling_process_handle);
  27. // RPC_S_NO_CALL_ACTIVE indicates that the caller is local process.
  28. if (status == RPC_S_NO_CALL_ACTIVE)
  29. return base::Process::Current();
  30. if (status != RPC_S_OK)
  31. return base::Process();
  32. return base::Process(calling_process_handle);
  33. }
  34. } // namespace
  35. HRESULT Elevator::RunRecoveryCRXElevated(const wchar_t* crx_path,
  36. const wchar_t* browser_appid,
  37. const wchar_t* browser_version,
  38. const wchar_t* session_id,
  39. DWORD caller_proc_id,
  40. ULONG_PTR* proc_handle) {
  41. base::win::ScopedHandle scoped_proc_handle;
  42. HRESULT hr = RunChromeRecoveryCRX(base::FilePath(crx_path), browser_appid,
  43. browser_version, session_id, caller_proc_id,
  44. &scoped_proc_handle);
  45. *proc_handle = base::win::HandleToUint32(scoped_proc_handle.Take());
  46. return hr;
  47. }
  48. HRESULT Elevator::EncryptData(ProtectionLevel protection_level,
  49. const BSTR plaintext,
  50. BSTR* ciphertext,
  51. DWORD* last_error) {
  52. if (protection_level > ProtectionLevel::PATH_VALIDATION)
  53. return E_INVALIDARG;
  54. UINT length = ::SysStringByteLen(plaintext);
  55. if (!length)
  56. return E_INVALIDARG;
  57. HRESULT hr = ::CoImpersonateClient();
  58. if (FAILED(hr))
  59. return hr;
  60. DATA_BLOB intermediate = {};
  61. {
  62. base::ScopedClosureRunner revert_to_self(
  63. base::BindOnce([]() { ::CoRevertToSelf(); }));
  64. const auto calling_process = GetCallingProcess();
  65. if (!calling_process.IsValid())
  66. return kErrorCouldNotObtainCallingProcess;
  67. const std::string validation_data =
  68. GenerateValidationData(protection_level, calling_process);
  69. if (validation_data.empty())
  70. return kErrorCouldNotGenerateValidationData;
  71. std::string data_to_encrypt;
  72. AppendStringWithLength(validation_data, data_to_encrypt);
  73. AppendStringWithLength(
  74. std::string(reinterpret_cast<char*>(plaintext), length),
  75. data_to_encrypt);
  76. DATA_BLOB input = {};
  77. input.cbData = base::checked_cast<DWORD>(data_to_encrypt.length());
  78. input.pbData = const_cast<BYTE*>(
  79. reinterpret_cast<const BYTE*>(data_to_encrypt.data()));
  80. if (!::CryptProtectData(&input, L"", nullptr, nullptr, nullptr, 0,
  81. &intermediate)) {
  82. *last_error = ::GetLastError();
  83. return kErrorCouldNotEncryptWithUserContext;
  84. }
  85. }
  86. DATA_BLOB output = {};
  87. {
  88. base::win::ScopedLocalAlloc intermediate_freer(intermediate.pbData);
  89. if (!::CryptProtectData(&intermediate, L"", nullptr, nullptr, nullptr, 0,
  90. &output)) {
  91. *last_error = ::GetLastError();
  92. return kErrorCouldNotEncryptWithSystemContext;
  93. }
  94. }
  95. base::win::ScopedLocalAlloc output_freer(output.pbData);
  96. *ciphertext = ::SysAllocStringByteLen(reinterpret_cast<LPCSTR>(output.pbData),
  97. output.cbData);
  98. if (!*ciphertext)
  99. return E_OUTOFMEMORY;
  100. return S_OK;
  101. }
  102. HRESULT Elevator::DecryptData(const BSTR ciphertext,
  103. BSTR* plaintext,
  104. DWORD* last_error) {
  105. UINT length = ::SysStringByteLen(ciphertext);
  106. if (!length)
  107. return E_INVALIDARG;
  108. DATA_BLOB input = {};
  109. input.cbData = length;
  110. input.pbData = reinterpret_cast<BYTE*>(ciphertext);
  111. DATA_BLOB intermediate = {};
  112. // Decrypt using the SYSTEM dpapi store.
  113. if (!::CryptUnprotectData(&input, nullptr, nullptr, nullptr, nullptr, 0,
  114. &intermediate)) {
  115. *last_error = ::GetLastError();
  116. return kErrorCouldNotDecryptWithSystemContext;
  117. }
  118. base::win::ScopedLocalAlloc intermediate_freer(intermediate.pbData);
  119. HRESULT hr = ::CoImpersonateClient();
  120. if (FAILED(hr))
  121. return hr;
  122. std::string plaintext_str;
  123. {
  124. DATA_BLOB output = {};
  125. base::ScopedClosureRunner revert_to_self(
  126. base::BindOnce([]() { ::CoRevertToSelf(); }));
  127. // Decrypt using the user store.
  128. if (!::CryptUnprotectData(&intermediate, nullptr, nullptr, nullptr, nullptr,
  129. 0, &output)) {
  130. *last_error = ::GetLastError();
  131. return kErrorCouldNotDecryptWithUserContext;
  132. }
  133. base::win::ScopedLocalAlloc output_freer(output.pbData);
  134. std::string mutable_plaintext(reinterpret_cast<char*>(output.pbData),
  135. output.cbData);
  136. std::string validation_data = PopFromStringFront(mutable_plaintext);
  137. if (validation_data.empty())
  138. return E_INVALIDARG;
  139. const auto process = GetCallingProcess();
  140. if (!process.IsValid()) {
  141. *last_error = ::GetLastError();
  142. return kErrorCouldNotObtainCallingProcess;
  143. }
  144. // Validation should always be done as the caller.
  145. bool validated = ValidateData(process, validation_data);
  146. if (!validated) {
  147. *last_error = ::GetLastError();
  148. return kValidationDidNotPass;
  149. }
  150. plaintext_str = PopFromStringFront(mutable_plaintext);
  151. }
  152. *plaintext =
  153. ::SysAllocStringByteLen(plaintext_str.c_str(), plaintext_str.length());
  154. if (!*plaintext)
  155. return E_OUTOFMEMORY;
  156. return S_OK;
  157. }
  158. // static
  159. void Elevator::AppendStringWithLength(const std::string& to_append,
  160. std::string& base) {
  161. uint32_t size = base::checked_cast<uint32_t>(to_append.length());
  162. base.append(reinterpret_cast<char*>(&size), sizeof(size));
  163. base.append(to_append);
  164. }
  165. // static
  166. std::string Elevator::PopFromStringFront(std::string& str) {
  167. uint32_t size;
  168. if (str.length() < sizeof(size))
  169. return std::string();
  170. auto it = str.begin();
  171. // Obtain the size.
  172. memcpy(&size, str.c_str(), sizeof(size));
  173. // Skip over the size field.
  174. std::string value;
  175. if (size) {
  176. it += sizeof(size);
  177. // Pull the string out.
  178. value.assign(it, it + size);
  179. DCHECK_EQ(value.length(), base::checked_cast<std::string::size_type>(size));
  180. }
  181. // Trim the string to the remainder.
  182. str = str.substr(sizeof(size) + size);
  183. return value;
  184. }
  185. } // namespace elevation_service