Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome_frame/module_utils.h" | 5 #include "chrome_frame/module_utils.h" |
| 6 | 6 |
| 7 #include <aclapi.h> | |
| 7 #include <atlbase.h> | 8 #include <atlbase.h> |
| 9 #include <atlsecurity.h> | |
| 10 #include <sddl.h> | |
| 11 | |
| 8 #include "base/file_path.h" | 12 #include "base/file_path.h" |
| 9 #include "base/file_version_info.h" | 13 #include "base/file_version_info.h" |
| 10 #include "base/logging.h" | 14 #include "base/logging.h" |
| 11 #include "base/path_service.h" | 15 #include "base/path_service.h" |
| 12 #include "base/shared_memory.h" | 16 #include "base/shared_memory.h" |
| 17 #include "base/sys_info.h" | |
| 13 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
| 14 #include "base/version.h" | 19 #include "base/version.h" |
| 20 #include "chrome_frame/utils.h" | |
| 15 | 21 |
| 16 const char kSharedMemoryName[] = "ChromeFrameVersionBeacon"; | 22 const wchar_t kSharedMemoryName[] = L"ChromeFrameVersionBeacon_"; |
| 17 const uint32 kSharedMemorySize = 128; | 23 const uint32 kSharedMemorySize = 128; |
| 18 const uint32 kSharedMemoryLockTimeoutMs = 1000; | 24 const uint32 kSharedMemoryLockTimeoutMs = 1000; |
| 19 | 25 |
| 20 // static | 26 // static |
| 21 DllRedirector::DllRedirector() : first_module_handle_(NULL) { | 27 DllRedirector::DllRedirector() : first_module_handle_(NULL) { |
| 22 // TODO(robertshield): Correctly construct the profile name here. Also allow | 28 // TODO(robertshield): Allow for overrides to be taken from the environment. |
| 23 // for overrides to be taken from the environment. | 29 std::wstring beacon_name(kSharedMemoryName); |
| 24 shared_memory_.reset(new base::SharedMemory(ASCIIToWide(kSharedMemoryName))); | 30 beacon_name += GetHostProcessName(false); |
| 31 shared_memory_.reset(new base::SharedMemory(beacon_name)); | |
| 25 } | 32 } |
| 26 | 33 |
| 27 DllRedirector::DllRedirector(const char* shared_memory_name) | 34 DllRedirector::DllRedirector(const char* shared_memory_name) |
| 28 : shared_memory_name_(shared_memory_name), first_module_handle_(NULL) { | 35 : shared_memory_name_(shared_memory_name), first_module_handle_(NULL) { |
| 29 // TODO(robertshield): Correctly construct the profile name here. Also allow | |
| 30 // for overrides to be taken from the environment. | |
| 31 shared_memory_.reset(new base::SharedMemory(ASCIIToWide(shared_memory_name))); | 36 shared_memory_.reset(new base::SharedMemory(ASCIIToWide(shared_memory_name))); |
| 32 } | 37 } |
| 33 | 38 |
| 34 DllRedirector::~DllRedirector() { | 39 DllRedirector::~DllRedirector() { |
| 35 if (first_module_handle_) { | 40 if (first_module_handle_) { |
| 36 if (first_module_handle_ != reinterpret_cast<HMODULE>(&__ImageBase)) { | 41 if (first_module_handle_ != reinterpret_cast<HMODULE>(&__ImageBase)) { |
| 37 FreeLibrary(first_module_handle_); | 42 FreeLibrary(first_module_handle_); |
| 38 } | 43 } |
| 39 first_module_handle_ = NULL; | 44 first_module_handle_ = NULL; |
| 40 } | 45 } |
| 41 UnregisterAsFirstCFModule(); | 46 UnregisterAsFirstCFModule(); |
| 42 } | 47 } |
| 43 | 48 |
| 49 bool DllRedirector::GetLockSecurityAttributes(CSecurityAttributes* sec_attr) { | |
|
tommi (sloooow) - chröme
2010/11/15 19:33:30
change name to "BuildSecurityAttributesForLock" or
robertshield
2010/11/15 20:32:18
Done.
| |
| 50 DCHECK(sec_attr); | |
| 51 int32 major_version, minor_version, fix_version; | |
| 52 base::SysInfo::OperatingSystemVersionNumbers(&major_version, | |
| 53 &minor_version, | |
| 54 &fix_version); | |
| 55 if (major_version < 6) { | |
| 56 // Don't bother with changing ACLs on pre-vista. | |
| 57 return false; | |
| 58 } | |
| 59 | |
| 60 bool success = false; | |
| 61 | |
| 62 // Fill out the rest of the security descriptor from the process token. | |
| 63 CAccessToken token; | |
| 64 if (token.GetProcessToken(TOKEN_QUERY)) { | |
| 65 CSecurityDesc security_desc; | |
| 66 if (security_desc.FromString(L"S:(ML;;NW;;;LW)")) { | |
|
tommi (sloooow) - chröme
2010/11/15 19:33:30
Add a comment that explains what the string means
robertshield
2010/11/15 20:32:18
Done.
| |
| 67 CSid sid_owner; | |
| 68 if (token.GetOwner(&sid_owner)) { | |
| 69 security_desc.SetOwner(sid_owner); | |
| 70 } else { | |
| 71 NOTREACHED() << "Could not set owner."; | |
|
tommi (sloooow) - chröme
2010/11/15 19:33:30
set -> get
robertshield
2010/11/15 20:32:18
Done.
| |
| 72 } | |
| 73 CSid sid_group; | |
| 74 if (token.GetPrimaryGroup(&sid_group)) { | |
| 75 security_desc.SetGroup(sid_group); | |
| 76 } else { | |
| 77 NOTREACHED() << "Could not set group."; | |
|
tommi (sloooow) - chröme
2010/11/15 19:33:30
set -> get
robertshield
2010/11/15 20:32:18
Done.
| |
| 78 } | |
| 79 CDacl dacl; | |
| 80 if (token.GetDefaultDacl(&dacl)) { | |
| 81 // Add an access control entry mask for the current user. | |
| 82 // This is what grants this user access from lower integrity levels. | |
| 83 CSid sid_user; | |
| 84 if (token.GetUser(&sid_user)) { | |
| 85 success = dacl.AddAllowedAce(sid_user, MUTEX_ALL_ACCESS); | |
| 86 security_desc.SetDacl(dacl); | |
| 87 sec_attr->Set(security_desc); | |
| 88 } | |
| 89 } | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 return success; | |
| 94 } | |
| 95 | |
| 96 bool DllRedirector::SetFileMappingToReadOnly(base::SharedMemoryHandle mapping) { | |
| 97 bool success = false; | |
| 98 | |
| 99 CAccessToken token; | |
| 100 if (token.GetProcessToken(TOKEN_QUERY)) { | |
| 101 CSid sid_user; | |
| 102 if (token.GetUser(&sid_user)) { | |
| 103 CDacl dacl; | |
| 104 dacl.AddAllowedAce(sid_user, STANDARD_RIGHTS_READ | FILE_MAP_READ); | |
| 105 success = AtlSetDacl(mapping, SE_KERNEL_OBJECT, dacl); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 return success; | |
| 110 } | |
| 111 | |
| 112 | |
| 44 bool DllRedirector::RegisterAsFirstCFModule() { | 113 bool DllRedirector::RegisterAsFirstCFModule() { |
| 45 DCHECK(first_module_handle_ == NULL); | 114 DCHECK(first_module_handle_ == NULL); |
| 46 | 115 |
| 47 // Build our own file version outside of the lock: | 116 // Build our own file version outside of the lock: |
| 48 scoped_ptr<Version> our_version(GetCurrentModuleVersion()); | 117 scoped_ptr<Version> our_version(GetCurrentModuleVersion()); |
| 49 | 118 |
| 50 // We sadly can't use the autolock here since we want to have a timeout. | 119 // We sadly can't use the autolock here since we want to have a timeout. |
| 51 // Be careful not to return while holding the lock. Also, attempt to do as | 120 // Be careful not to return while holding the lock. Also, attempt to do as |
| 52 // little as possible while under this lock. | 121 // little as possible while under this lock. |
| 53 bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs); | 122 |
| 123 bool lock_acquired = false; | |
| 124 CSecurityAttributes sec_attr; | |
| 125 if (GetLockSecurityAttributes(&sec_attr)) { | |
| 126 lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, &sec_attr); | |
| 127 } else { | |
| 128 lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL); | |
| 129 } | |
| 54 | 130 |
| 55 if (!lock_acquired) { | 131 if (!lock_acquired) { |
| 56 // We couldn't get the lock in a reasonable amount of time, so fall | 132 // We couldn't get the lock in a reasonable amount of time, so fall |
| 57 // back to loading our current version. We return true to indicate that the | 133 // back to loading our current version. We return true to indicate that the |
| 58 // caller should not attempt to delegate to an already loaded version. | 134 // caller should not attempt to delegate to an already loaded version. |
| 59 dll_version_.swap(our_version); | 135 dll_version_.swap(our_version); |
| 60 first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase); | 136 first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase); |
| 61 return true; | 137 return true; |
| 62 } | 138 } |
| 63 | 139 |
| 64 bool created_beacon = true; | 140 bool created_beacon = true; |
| 65 bool result = shared_memory_->CreateNamed(shared_memory_name_.c_str(), | 141 bool result = shared_memory_->CreateNamed(shared_memory_name_.c_str(), |
| 66 false, // open_existing | 142 false, // open_existing |
| 67 kSharedMemorySize); | 143 kSharedMemorySize); |
| 68 | 144 |
| 69 if (!result) { | 145 if (result) { |
| 146 // We created the beacon, now we need to mutate the security attributes | |
| 147 // on the shared memory to allow read-only access and let low-integrity | |
| 148 // processes open it. | |
| 149 bool acls_set = SetFileMappingToReadOnly(shared_memory_->handle()); | |
| 150 DCHECK(acls_set); | |
| 151 } else { | |
| 70 created_beacon = false; | 152 created_beacon = false; |
| 71 | 153 |
| 72 // We failed to create the shared memory segment, suggesting it may already | 154 // We failed to create the shared memory segment, suggesting it may already |
| 73 // exist: try to create it read-only. | 155 // exist: try to create it read-only. |
| 74 result = shared_memory_->Open(shared_memory_name_.c_str(), | 156 result = shared_memory_->Open(shared_memory_name_.c_str(), |
| 75 true /* read_only */); | 157 true /* read_only */); |
| 76 } | 158 } |
| 77 | 159 |
| 78 if (result) { | 160 if (result) { |
| 79 // Map in the whole thing. | 161 // Map in the whole thing. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 } | 198 } |
| 117 | 199 |
| 118 // Matching Unlock. | 200 // Matching Unlock. |
| 119 shared_memory_->Unlock(); | 201 shared_memory_->Unlock(); |
| 120 | 202 |
| 121 return created_beacon; | 203 return created_beacon; |
| 122 } | 204 } |
| 123 | 205 |
| 124 void DllRedirector::UnregisterAsFirstCFModule() { | 206 void DllRedirector::UnregisterAsFirstCFModule() { |
| 125 if (base::SharedMemory::IsHandleValid(shared_memory_->handle())) { | 207 if (base::SharedMemory::IsHandleValid(shared_memory_->handle())) { |
| 126 bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs); | 208 bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL); |
| 127 if (lock_acquired) { | 209 if (lock_acquired) { |
| 128 // Free our handles. The last closed handle SHOULD result in it being | 210 // Free our handles. The last closed handle SHOULD result in it being |
| 129 // deleted. | 211 // deleted. |
| 130 shared_memory_->Close(); | 212 shared_memory_->Close(); |
| 131 shared_memory_->Unlock(); | 213 shared_memory_->Unlock(); |
| 132 } | 214 } |
| 133 } | 215 } |
| 134 } | 216 } |
| 135 | 217 |
| 136 LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr() { | 218 LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr() { |
| 137 HMODULE first_module_handle = GetFirstModule(); | 219 HMODULE first_module_handle = GetFirstModule(); |
| 138 | 220 |
| 139 LPFNGETCLASSOBJECT proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( | 221 LPFNGETCLASSOBJECT proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( |
| 140 GetProcAddress(first_module_handle, "DllGetClassObject")); | 222 GetProcAddress(first_module_handle, "DllGetClassObject")); |
| 141 if (!proc_ptr) { | 223 if (!proc_ptr) { |
| 142 DLOG(ERROR) << "DllRedirector: Could get address of DllGetClassObject " | 224 DPLOG(ERROR) << "DllRedirector: Could get address of DllGetClassObject " |
| 143 "from first loaded module, GLE: " | 225 "from first loaded module, GLE: "; |
|
tommi (sloooow) - chröme
2010/11/15 19:33:30
remove ", GLE: "
robertshield
2010/11/15 20:32:18
Done.
| |
| 144 << GetLastError(); | |
| 145 // Oh boink, the first module we loaded was somehow bogus, make ourselves | 226 // Oh boink, the first module we loaded was somehow bogus, make ourselves |
| 146 // the first module again. | 227 // the first module again. |
| 147 first_module_handle = reinterpret_cast<HMODULE>(&__ImageBase); | 228 first_module_handle = reinterpret_cast<HMODULE>(&__ImageBase); |
| 148 } | 229 } |
| 149 return proc_ptr; | 230 return proc_ptr; |
| 150 } | 231 } |
| 151 | 232 |
| 152 Version* DllRedirector::GetCurrentModuleVersion() { | 233 Version* DllRedirector::GetCurrentModuleVersion() { |
| 153 scoped_ptr<FileVersionInfo> file_version_info( | 234 scoped_ptr<FileVersionInfo> file_version_info( |
| 154 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | 235 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 185 PathService::Get(base::DIR_MODULE, &module_path); | 266 PathService::Get(base::DIR_MODULE, &module_path); |
| 186 DCHECK(!module_path.empty()); | 267 DCHECK(!module_path.empty()); |
| 187 | 268 |
| 188 FilePath module_name = module_path.BaseName(); | 269 FilePath module_name = module_path.BaseName(); |
| 189 module_path = module_path.DirName() | 270 module_path = module_path.DirName() |
| 190 .Append(ASCIIToWide(version->GetString())) | 271 .Append(ASCIIToWide(version->GetString())) |
| 191 .Append(module_name); | 272 .Append(module_name); |
| 192 | 273 |
| 193 HMODULE hmodule = LoadLibrary(module_path.value().c_str()); | 274 HMODULE hmodule = LoadLibrary(module_path.value().c_str()); |
| 194 if (hmodule == NULL) { | 275 if (hmodule == NULL) { |
| 195 DLOG(ERROR) << "Could not load reported module version " | 276 DPLOG(ERROR) << "Could not load reported module version " |
| 196 << version->GetString(); | 277 << version->GetString(); |
| 197 } | 278 } |
| 198 | 279 |
| 199 return hmodule; | 280 return hmodule; |
| 200 } | 281 } |
| 201 | 282 |
| OLD | NEW |