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::BuildSecurityAttributesForLock( |
| 50 CSecurityAttributes* sec_attr) { |
| 51 DCHECK(sec_attr); |
| 52 int32 major_version, minor_version, fix_version; |
| 53 base::SysInfo::OperatingSystemVersionNumbers(&major_version, |
| 54 &minor_version, |
| 55 &fix_version); |
| 56 if (major_version < 6) { |
| 57 // Don't bother with changing ACLs on pre-vista. |
| 58 return false; |
| 59 } |
| 60 |
| 61 bool success = false; |
| 62 |
| 63 // Fill out the rest of the security descriptor from the process token. |
| 64 CAccessToken token; |
| 65 if (token.GetProcessToken(TOKEN_QUERY)) { |
| 66 CSecurityDesc security_desc; |
| 67 // Set the SACL from an SDDL string that allows access to low-integrity |
| 68 // processes. See http://msdn.microsoft.com/en-us/library/bb625958.aspx. |
| 69 if (security_desc.FromString(L"S:(ML;;NW;;;LW)")) { |
| 70 CSid sid_owner; |
| 71 if (token.GetOwner(&sid_owner)) { |
| 72 security_desc.SetOwner(sid_owner); |
| 73 } else { |
| 74 NOTREACHED() << "Could not get owner."; |
| 75 } |
| 76 CSid sid_group; |
| 77 if (token.GetPrimaryGroup(&sid_group)) { |
| 78 security_desc.SetGroup(sid_group); |
| 79 } else { |
| 80 NOTREACHED() << "Could not get group."; |
| 81 } |
| 82 CDacl dacl; |
| 83 if (token.GetDefaultDacl(&dacl)) { |
| 84 // Add an access control entry mask for the current user. |
| 85 // This is what grants this user access from lower integrity levels. |
| 86 CSid sid_user; |
| 87 if (token.GetUser(&sid_user)) { |
| 88 success = dacl.AddAllowedAce(sid_user, MUTEX_ALL_ACCESS); |
| 89 security_desc.SetDacl(dacl); |
| 90 sec_attr->Set(security_desc); |
| 91 } |
| 92 } |
| 93 } |
| 94 } |
| 95 |
| 96 return success; |
| 97 } |
| 98 |
| 99 bool DllRedirector::SetFileMappingToReadOnly(base::SharedMemoryHandle mapping) { |
| 100 bool success = false; |
| 101 |
| 102 CAccessToken token; |
| 103 if (token.GetProcessToken(TOKEN_QUERY)) { |
| 104 CSid sid_user; |
| 105 if (token.GetUser(&sid_user)) { |
| 106 CDacl dacl; |
| 107 dacl.AddAllowedAce(sid_user, STANDARD_RIGHTS_READ | FILE_MAP_READ); |
| 108 success = AtlSetDacl(mapping, SE_KERNEL_OBJECT, dacl); |
| 109 } |
| 110 } |
| 111 |
| 112 return success; |
| 113 } |
| 114 |
| 115 |
44 bool DllRedirector::RegisterAsFirstCFModule() { | 116 bool DllRedirector::RegisterAsFirstCFModule() { |
45 DCHECK(first_module_handle_ == NULL); | 117 DCHECK(first_module_handle_ == NULL); |
46 | 118 |
47 // Build our own file version outside of the lock: | 119 // Build our own file version outside of the lock: |
48 scoped_ptr<Version> our_version(GetCurrentModuleVersion()); | 120 scoped_ptr<Version> our_version(GetCurrentModuleVersion()); |
49 | 121 |
50 // We sadly can't use the autolock here since we want to have a timeout. | 122 // 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 | 123 // Be careful not to return while holding the lock. Also, attempt to do as |
52 // little as possible while under this lock. | 124 // little as possible while under this lock. |
53 bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs); | 125 |
| 126 bool lock_acquired = false; |
| 127 CSecurityAttributes sec_attr; |
| 128 if (BuildSecurityAttributesForLock(&sec_attr)) { |
| 129 lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, &sec_attr); |
| 130 } else { |
| 131 lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL); |
| 132 } |
54 | 133 |
55 if (!lock_acquired) { | 134 if (!lock_acquired) { |
56 // We couldn't get the lock in a reasonable amount of time, so fall | 135 // 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 | 136 // 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. | 137 // caller should not attempt to delegate to an already loaded version. |
59 dll_version_.swap(our_version); | 138 dll_version_.swap(our_version); |
60 first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase); | 139 first_module_handle_ = reinterpret_cast<HMODULE>(&__ImageBase); |
61 return true; | 140 return true; |
62 } | 141 } |
63 | 142 |
64 bool created_beacon = true; | 143 bool created_beacon = true; |
65 bool result = shared_memory_->CreateNamed(shared_memory_name_.c_str(), | 144 bool result = shared_memory_->CreateNamed(shared_memory_name_.c_str(), |
66 false, // open_existing | 145 false, // open_existing |
67 kSharedMemorySize); | 146 kSharedMemorySize); |
68 | 147 |
69 if (!result) { | 148 if (result) { |
| 149 // We created the beacon, now we need to mutate the security attributes |
| 150 // on the shared memory to allow read-only access and let low-integrity |
| 151 // processes open it. |
| 152 bool acls_set = SetFileMappingToReadOnly(shared_memory_->handle()); |
| 153 DCHECK(acls_set); |
| 154 } else { |
70 created_beacon = false; | 155 created_beacon = false; |
71 | 156 |
72 // We failed to create the shared memory segment, suggesting it may already | 157 // We failed to create the shared memory segment, suggesting it may already |
73 // exist: try to create it read-only. | 158 // exist: try to create it read-only. |
74 result = shared_memory_->Open(shared_memory_name_.c_str(), | 159 result = shared_memory_->Open(shared_memory_name_.c_str(), |
75 true /* read_only */); | 160 true /* read_only */); |
76 } | 161 } |
77 | 162 |
78 if (result) { | 163 if (result) { |
79 // Map in the whole thing. | 164 // Map in the whole thing. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 } | 201 } |
117 | 202 |
118 // Matching Unlock. | 203 // Matching Unlock. |
119 shared_memory_->Unlock(); | 204 shared_memory_->Unlock(); |
120 | 205 |
121 return created_beacon; | 206 return created_beacon; |
122 } | 207 } |
123 | 208 |
124 void DllRedirector::UnregisterAsFirstCFModule() { | 209 void DllRedirector::UnregisterAsFirstCFModule() { |
125 if (base::SharedMemory::IsHandleValid(shared_memory_->handle())) { | 210 if (base::SharedMemory::IsHandleValid(shared_memory_->handle())) { |
126 bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs); | 211 bool lock_acquired = shared_memory_->Lock(kSharedMemoryLockTimeoutMs, NULL); |
127 if (lock_acquired) { | 212 if (lock_acquired) { |
128 // Free our handles. The last closed handle SHOULD result in it being | 213 // Free our handles. The last closed handle SHOULD result in it being |
129 // deleted. | 214 // deleted. |
130 shared_memory_->Close(); | 215 shared_memory_->Close(); |
131 shared_memory_->Unlock(); | 216 shared_memory_->Unlock(); |
132 } | 217 } |
133 } | 218 } |
134 } | 219 } |
135 | 220 |
136 LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr() { | 221 LPFNGETCLASSOBJECT DllRedirector::GetDllGetClassObjectPtr() { |
137 HMODULE first_module_handle = GetFirstModule(); | 222 HMODULE first_module_handle = GetFirstModule(); |
138 | 223 |
139 LPFNGETCLASSOBJECT proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( | 224 LPFNGETCLASSOBJECT proc_ptr = reinterpret_cast<LPFNGETCLASSOBJECT>( |
140 GetProcAddress(first_module_handle, "DllGetClassObject")); | 225 GetProcAddress(first_module_handle, "DllGetClassObject")); |
141 if (!proc_ptr) { | 226 if (!proc_ptr) { |
142 DLOG(ERROR) << "DllRedirector: Could get address of DllGetClassObject " | 227 DPLOG(ERROR) << "DllRedirector: Could not get address of DllGetClassObject " |
143 "from first loaded module, GLE: " | 228 "from first loaded module."; |
144 << GetLastError(); | |
145 // Oh boink, the first module we loaded was somehow bogus, make ourselves | 229 // Oh boink, the first module we loaded was somehow bogus, make ourselves |
146 // the first module again. | 230 // the first module again. |
147 first_module_handle = reinterpret_cast<HMODULE>(&__ImageBase); | 231 first_module_handle = reinterpret_cast<HMODULE>(&__ImageBase); |
148 } | 232 } |
149 return proc_ptr; | 233 return proc_ptr; |
150 } | 234 } |
151 | 235 |
152 Version* DllRedirector::GetCurrentModuleVersion() { | 236 Version* DllRedirector::GetCurrentModuleVersion() { |
153 scoped_ptr<FileVersionInfo> file_version_info( | 237 scoped_ptr<FileVersionInfo> file_version_info( |
154 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | 238 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); |
(...skipping 30 matching lines...) Expand all Loading... |
185 PathService::Get(base::DIR_MODULE, &module_path); | 269 PathService::Get(base::DIR_MODULE, &module_path); |
186 DCHECK(!module_path.empty()); | 270 DCHECK(!module_path.empty()); |
187 | 271 |
188 FilePath module_name = module_path.BaseName(); | 272 FilePath module_name = module_path.BaseName(); |
189 module_path = module_path.DirName() | 273 module_path = module_path.DirName() |
190 .Append(ASCIIToWide(version->GetString())) | 274 .Append(ASCIIToWide(version->GetString())) |
191 .Append(module_name); | 275 .Append(module_name); |
192 | 276 |
193 HMODULE hmodule = LoadLibrary(module_path.value().c_str()); | 277 HMODULE hmodule = LoadLibrary(module_path.value().c_str()); |
194 if (hmodule == NULL) { | 278 if (hmodule == NULL) { |
195 DLOG(ERROR) << "Could not load reported module version " | 279 DPLOG(ERROR) << "Could not load reported module version " |
196 << version->GetString(); | 280 << version->GetString(); |
197 } | 281 } |
198 | 282 |
199 return hmodule; | 283 return hmodule; |
200 } | 284 } |
201 | 285 |
OLD | NEW |