ProcThreadAttributes.h (4877B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_ProcThreadAttributes_h 8 #define mozilla_ProcThreadAttributes_h 9 10 #include <windows.h> 11 12 #include <utility> 13 14 #include "mozilla/UniquePtr.h" 15 #include "mozilla/Vector.h" 16 17 namespace mozilla { 18 19 class MOZ_RAII ProcThreadAttributes final { 20 struct ProcThreadAttributeListDeleter { 21 void operator()(LPPROC_THREAD_ATTRIBUTE_LIST aList) { 22 ::DeleteProcThreadAttributeList(aList); 23 delete[] reinterpret_cast<char*>(aList); 24 } 25 }; 26 27 using ProcThreadAttributeListPtr = 28 UniquePtr<_PROC_THREAD_ATTRIBUTE_LIST, ProcThreadAttributeListDeleter>; 29 30 public: 31 ProcThreadAttributes() : mMitigationPolicies(0) {} 32 33 ~ProcThreadAttributes() = default; 34 35 ProcThreadAttributes(const ProcThreadAttributes&) = delete; 36 ProcThreadAttributes(ProcThreadAttributes&&) = delete; 37 ProcThreadAttributes& operator=(const ProcThreadAttributes&) = delete; 38 ProcThreadAttributes& operator=(ProcThreadAttributes&&) = delete; 39 40 void AddMitigationPolicy(DWORD64 aPolicy) { mMitigationPolicies |= aPolicy; } 41 42 bool AddInheritableHandle(HANDLE aHandle) { 43 DWORD type = ::GetFileType(aHandle); 44 if (type != FILE_TYPE_DISK && type != FILE_TYPE_PIPE) { 45 return false; 46 } 47 48 if (!::SetHandleInformation(aHandle, HANDLE_FLAG_INHERIT, 49 HANDLE_FLAG_INHERIT)) { 50 return false; 51 } 52 53 return mInheritableHandles.append(aHandle); 54 } 55 56 template <size_t N> 57 bool AddInheritableHandles(HANDLE (&aHandles)[N]) { 58 bool ok = true; 59 for (auto handle : aHandles) { 60 ok &= AddInheritableHandle(handle); 61 } 62 63 return ok; 64 } 65 66 bool HasMitigationPolicies() const { return !!mMitigationPolicies; } 67 68 bool HasInheritableHandles() const { return !mInheritableHandles.empty(); } 69 70 /** 71 * @return false if the STARTUPINFOEXW::lpAttributeList was set to null 72 * as expected based on the state of |this|; 73 * true if the STARTUPINFOEXW::lpAttributeList was set to 74 * non-null; 75 */ 76 LauncherResult<bool> AssignTo(STARTUPINFOEXW& aSiex) { 77 ZeroMemory(&aSiex, sizeof(STARTUPINFOEXW)); 78 79 // We'll set the size to sizeof(STARTUPINFOW) until we determine whether the 80 // extended fields will be used. 81 aSiex.StartupInfo.cb = sizeof(STARTUPINFOW); 82 83 DWORD numAttributes = 0; 84 if (HasMitigationPolicies()) { 85 ++numAttributes; 86 } 87 88 if (HasInheritableHandles()) { 89 ++numAttributes; 90 } 91 92 if (!numAttributes) { 93 return false; 94 } 95 96 SIZE_T listSize = 0; 97 if (!::InitializeProcThreadAttributeList(nullptr, numAttributes, 0, 98 &listSize)) { 99 DWORD err = ::GetLastError(); 100 if (err != ERROR_INSUFFICIENT_BUFFER) { 101 return LAUNCHER_ERROR_FROM_WIN32(err); 102 } 103 } 104 105 auto buf = MakeUnique<char[]>(listSize); 106 107 LPPROC_THREAD_ATTRIBUTE_LIST tmpList = 108 reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(buf.get()); 109 110 if (!::InitializeProcThreadAttributeList(tmpList, numAttributes, 0, 111 &listSize)) { 112 return LAUNCHER_ERROR_FROM_LAST(); 113 } 114 115 // Transfer buf to a ProcThreadAttributeListPtr - now that the list is 116 // initialized, we are no longer dealing with a plain old char array. We 117 // must now deinitialize the attribute list before deallocating the 118 // underlying buffer. 119 ProcThreadAttributeListPtr attrList( 120 reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(buf.release())); 121 122 if (mMitigationPolicies) { 123 if (!::UpdateProcThreadAttribute( 124 attrList.get(), 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, 125 &mMitigationPolicies, sizeof(mMitigationPolicies), nullptr, 126 nullptr)) { 127 return LAUNCHER_ERROR_FROM_LAST(); 128 } 129 } 130 131 if (!mInheritableHandles.empty()) { 132 if (!::UpdateProcThreadAttribute( 133 attrList.get(), 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, 134 mInheritableHandles.begin(), 135 mInheritableHandles.length() * sizeof(HANDLE), nullptr, 136 nullptr)) { 137 return LAUNCHER_ERROR_FROM_LAST(); 138 } 139 } 140 141 mAttrList = std::move(attrList); 142 aSiex.lpAttributeList = mAttrList.get(); 143 aSiex.StartupInfo.cb = sizeof(STARTUPINFOEXW); 144 return true; 145 } 146 147 private: 148 static const uint32_t kNumInline = 3; // Inline storage for the std handles 149 150 DWORD64 mMitigationPolicies; 151 Vector<HANDLE, kNumInline> mInheritableHandles; 152 ProcThreadAttributeListPtr mAttrList; 153 }; 154 155 } // namespace mozilla 156 157 #endif // mozilla_ProcThreadAttributes_h