| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "content/common/sandbox_policy.h" | 5 #include "content/common/sandbox_policy.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/debug/debugger.h" | 10 #include "base/debug/debugger.h" |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 L"pavshookwow.dll", // Panda Antivirus. | 61 L"pavshookwow.dll", // Panda Antivirus. |
| 62 L"pctavhook.dll", // PC Tools Antivirus. | 62 L"pctavhook.dll", // PC Tools Antivirus. |
| 63 L"pctgmhk.dll", // PC Tools Spyware Doctor. | 63 L"pctgmhk.dll", // PC Tools Spyware Doctor. |
| 64 L"prntrack.dll", // Pharos Systems. | 64 L"prntrack.dll", // Pharos Systems. |
| 65 L"radhslib.dll", // Radiant Naomi Internet Filter. | 65 L"radhslib.dll", // Radiant Naomi Internet Filter. |
| 66 L"radprlib.dll", // Radiant Naomi Internet Filter. | 66 L"radprlib.dll", // Radiant Naomi Internet Filter. |
| 67 L"rapportnikko.dll", // Trustware Rapport. | 67 L"rapportnikko.dll", // Trustware Rapport. |
| 68 L"rlhook.dll", // Trustware Bufferzone. | 68 L"rlhook.dll", // Trustware Bufferzone. |
| 69 L"rooksdol.dll", // Trustware Rapport. | 69 L"rooksdol.dll", // Trustware Rapport. |
| 70 L"rpchromebrowserrecordhelper.dll", // RealPlayer. | 70 L"rpchromebrowserrecordhelper.dll", // RealPlayer. |
| 71 L"rpmainbrowserrecordplugin.dll", // RealPlayer. | |
| 72 L"r3hook.dll", // Kaspersky Internet Security. | 71 L"r3hook.dll", // Kaspersky Internet Security. |
| 73 L"sahook.dll", // McAfee Site Advisor. | 72 L"sahook.dll", // McAfee Site Advisor. |
| 74 L"sbrige.dll", // Unknown. | 73 L"sbrige.dll", // Unknown. |
| 75 L"sc2hook.dll", // Supercopier 2. | 74 L"sc2hook.dll", // Supercopier 2. |
| 76 L"sguard.dll", // Iolo (System Guard). | 75 L"sguard.dll", // Iolo (System Guard). |
| 77 L"smum32.dll", // Spyware Doctor version 6. | 76 L"smum32.dll", // Spyware Doctor version 6. |
| 78 L"smumhook.dll", // Spyware Doctor version 5. | 77 L"smumhook.dll", // Spyware Doctor version 5. |
| 79 L"ssldivx.dll", // DivX. | 78 L"ssldivx.dll", // DivX. |
| 80 L"syncor11.dll", // SynthCore Midi interface. | 79 L"syncor11.dll", // SynthCore Midi interface. |
| 81 L"systools.dll", // Panda Antivirus. | 80 L"systools.dll", // Panda Antivirus. |
| 82 L"tfwah.dll", // Threatfire (PC tools). | 81 L"tfwah.dll", // Threatfire (PC tools). |
| 83 L"ycwebcamerasource.ax", // Cyberlink Camera helper. | |
| 84 L"wblind.dll", // Stardock Object desktop. | 82 L"wblind.dll", // Stardock Object desktop. |
| 85 L"wbhelp.dll", // Stardock Object desktop. | 83 L"wbhelp.dll", // Stardock Object desktop. |
| 86 L"winstylerthemehelper.dll" // Tuneup utilities 2006. | 84 L"winstylerthemehelper.dll" // Tuneup utilities 2006. |
| 87 }; | 85 }; |
| 88 | 86 |
| 87 // The DLLs listed here are known (or under strong suspicion) of causing crashes |
| 88 // when they are loaded in the plugin process. |
| 89 const wchar_t* const kTroublesomePluginDlls[] = { |
| 90 L"rpmainbrowserrecordplugin.dll", // RealPlayer. |
| 91 L"ycwebcamerasource.ax" // Cyberlink Camera helper. |
| 92 }; |
| 93 |
| 89 // Adds the policy rules for the path and path\ with the semantic |access|. | 94 // Adds the policy rules for the path and path\ with the semantic |access|. |
| 90 // If |children| is set to true, we need to add the wildcard rules to also | 95 // If |children| is set to true, we need to add the wildcard rules to also |
| 91 // apply the rule to the subfiles and subfolders. | 96 // apply the rule to the subfiles and subfolders. |
| 92 bool AddDirectory(int path, const wchar_t* sub_dir, bool children, | 97 bool AddDirectory(int path, const wchar_t* sub_dir, bool children, |
| 93 sandbox::TargetPolicy::Semantics access, | 98 sandbox::TargetPolicy::Semantics access, |
| 94 sandbox::TargetPolicy* policy) { | 99 sandbox::TargetPolicy* policy) { |
| 95 FilePath directory; | 100 FilePath directory; |
| 96 if (!PathService::Get(path, &directory)) | 101 if (!PathService::Get(path, &directory)) |
| 97 return false; | 102 return false; |
| 98 | 103 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 // XP does not set the last error properly, so we bail out anyway. | 153 // XP does not set the last error properly, so we bail out anyway. |
| 149 return false; | 154 return false; |
| 150 } | 155 } |
| 151 if (!::GetLongPathName(path, path, arraysize(path))) | 156 if (!::GetLongPathName(path, path, arraysize(path))) |
| 152 return false; | 157 return false; |
| 153 FilePath fname(path); | 158 FilePath fname(path); |
| 154 return (fname.BaseName().value() == module_name); | 159 return (fname.BaseName().value() == module_name); |
| 155 } | 160 } |
| 156 | 161 |
| 157 // Adds a single dll by |module_name| into the |policy| blacklist. | 162 // Adds a single dll by |module_name| into the |policy| blacklist. |
| 158 // To minimize the list we only add an unload policy only if the dll is | 163 // If |check_in_browser| is true we only add an unload policy only if the dll |
| 159 // also loaded in this process. All the injected dlls of interest do this. | 164 // is also loaded in this process. |
| 160 void BlacklistAddOneDll(const wchar_t* module_name, | 165 void BlacklistAddOneDll(const wchar_t* module_name, |
| 166 bool check_in_browser, |
| 161 sandbox::TargetPolicy* policy) { | 167 sandbox::TargetPolicy* policy) { |
| 162 HMODULE module = ::GetModuleHandleW(module_name); | 168 HMODULE module = check_in_browser ? ::GetModuleHandleW(module_name) : NULL; |
| 163 if (!module) { | 169 if (!module) { |
| 164 // The module could have been loaded with a 8.3 short name. We use | 170 // The module could have been loaded with a 8.3 short name. We use |
| 165 // the most common case: 'thelongname.dll' becomes 'thelon~1.dll'. | 171 // the most common case: 'thelongname.dll' becomes 'thelon~1.dll'. |
| 166 std::wstring name(module_name); | 172 std::wstring name(module_name); |
| 167 size_t period = name.rfind(L'.'); | 173 size_t period = name.rfind(L'.'); |
| 168 DCHECK_NE(std::string::npos, period); | 174 DCHECK_NE(std::string::npos, period); |
| 169 DCHECK_LE(3U, (name.size() - period)); | 175 DCHECK_LE(3U, (name.size() - period)); |
| 170 if (period <= 8) | 176 if (period <= 8) |
| 171 return; | 177 return; |
| 172 std::wstring alt_name = name.substr(0, 6) + L"~1"; | 178 std::wstring alt_name = name.substr(0, 6) + L"~1"; |
| 173 alt_name += name.substr(period, name.size()); | 179 alt_name += name.substr(period, name.size()); |
| 174 module = ::GetModuleHandleW(alt_name.c_str()); | 180 if (check_in_browser) { |
| 175 if (!module) | 181 module = ::GetModuleHandleW(alt_name.c_str()); |
| 176 return; | 182 if (!module) |
| 177 // We found it, but because it only has 6 significant letters, we | 183 return; |
| 178 // want to make sure it is the right one. | 184 // We found it, but because it only has 6 significant letters, we |
| 179 if (!IsExpandedModuleName(module, module_name)) | 185 // want to make sure it is the right one. |
| 180 return; | 186 if (!IsExpandedModuleName(module, module_name)) |
| 187 return; |
| 188 } |
| 181 // Found a match. We add both forms to the policy. | 189 // Found a match. We add both forms to the policy. |
| 182 policy->AddDllToUnload(alt_name.c_str()); | 190 policy->AddDllToUnload(alt_name.c_str()); |
| 183 } | 191 } |
| 184 policy->AddDllToUnload(module_name); | 192 policy->AddDllToUnload(module_name); |
| 185 VLOG(1) << "dll to unload found: " << module_name; | 193 VLOG(1) << "dll to unload found: " << module_name; |
| 186 return; | 194 return; |
| 187 } | 195 } |
| 188 | 196 |
| 189 // Adds policy rules for unloaded the known dlls that cause chrome to crash. | 197 // Adds policy rules for unloaded the known dlls that cause chrome to crash. |
| 190 // Eviction of injected DLLs is done by the sandbox so that the injected module | 198 // Eviction of injected DLLs is done by the sandbox so that the injected module |
| 191 // does not get a chance to execute any code. | 199 // does not get a chance to execute any code. |
| 192 void AddDllEvictionPolicy(sandbox::TargetPolicy* policy) { | 200 void AddGenericDllEvictionPolicy(sandbox::TargetPolicy* policy) { |
| 193 for (int ix = 0; ix != arraysize(kTroublesomeDlls); ++ix) | 201 for (int ix = 0; ix != arraysize(kTroublesomeDlls); ++ix) |
| 194 BlacklistAddOneDll(kTroublesomeDlls[ix], policy); | 202 BlacklistAddOneDll(kTroublesomeDlls[ix], true, policy); |
| 203 } |
| 204 |
| 205 // Same as AddGenericDllEvictionPolicy but specifically for plugins. In this |
| 206 // case we add the blacklisted dlls even if they are not loaded in this process. |
| 207 void AddPluginDllEvictionPolicy(sandbox::TargetPolicy* policy) { |
| 208 for (int ix = 0; ix != arraysize(kTroublesomePluginDlls); ++ix) |
| 209 BlacklistAddOneDll(kTroublesomePluginDlls[ix], false, policy); |
| 195 } | 210 } |
| 196 | 211 |
| 197 // Returns the object path prepended with the current logon session. | 212 // Returns the object path prepended with the current logon session. |
| 198 string16 PrependWindowsSessionPath(const char16* object) { | 213 string16 PrependWindowsSessionPath(const char16* object) { |
| 199 // Cache this because it can't change after process creation. | 214 // Cache this because it can't change after process creation. |
| 200 uintptr_t s_session_id = 0; | 215 uintptr_t s_session_id = 0; |
| 201 if (s_session_id == 0) { | 216 if (s_session_id == 0) { |
| 202 HANDLE token; | 217 HANDLE token; |
| 203 DWORD session_id_length; | 218 DWORD session_id_length; |
| 204 DWORD session_id = 0; | 219 DWORD session_id = 0; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 | 290 |
| 276 if (base::win::GetVersion() > base::win::VERSION_XP) { | 291 if (base::win::GetVersion() > base::win::VERSION_XP) { |
| 277 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, | 292 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, |
| 278 sandbox::USER_LIMITED); | 293 sandbox::USER_LIMITED); |
| 279 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); | 294 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); |
| 280 } else { | 295 } else { |
| 281 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, | 296 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, |
| 282 sandbox::USER_LIMITED); | 297 sandbox::USER_LIMITED); |
| 283 } | 298 } |
| 284 | 299 |
| 285 AddDllEvictionPolicy(policy); | 300 AddGenericDllEvictionPolicy(policy); |
| 286 return true; | 301 return true; |
| 287 } | 302 } |
| 288 | 303 |
| 289 void AddPolicyForRenderer(sandbox::TargetPolicy* policy) { | 304 void AddPolicyForRenderer(sandbox::TargetPolicy* policy) { |
| 290 policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0); | 305 policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0); |
| 291 | 306 |
| 292 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED; | 307 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED; |
| 293 if (base::win::GetVersion() > base::win::VERSION_XP) { | 308 if (base::win::GetVersion() > base::win::VERSION_XP) { |
| 294 // On 2003/Vista the initial token has to be restricted if the main | 309 // On 2003/Vista the initial token has to be restricted if the main |
| 295 // token is restricted. | 310 // token is restricted. |
| 296 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS; | 311 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS; |
| 297 } | 312 } |
| 298 | 313 |
| 299 policy->SetTokenLevel(initial_token, sandbox::USER_LOCKDOWN); | 314 policy->SetTokenLevel(initial_token, sandbox::USER_LOCKDOWN); |
| 300 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); | 315 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); |
| 301 | 316 |
| 302 bool use_winsta = !CommandLine::ForCurrentProcess()->HasSwitch( | 317 bool use_winsta = !CommandLine::ForCurrentProcess()->HasSwitch( |
| 303 switches::kDisableAltWinstation); | 318 switches::kDisableAltWinstation); |
| 304 | 319 |
| 305 if (sandbox::SBOX_ALL_OK != policy->SetAlternateDesktop(use_winsta)) { | 320 if (sandbox::SBOX_ALL_OK != policy->SetAlternateDesktop(use_winsta)) { |
| 306 DLOG(WARNING) << "Failed to apply desktop security to the renderer"; | 321 DLOG(WARNING) << "Failed to apply desktop security to the renderer"; |
| 307 } | 322 } |
| 308 | 323 |
| 309 AddDllEvictionPolicy(policy); | 324 AddGenericDllEvictionPolicy(policy); |
| 310 } | 325 } |
| 311 | 326 |
| 312 // The Pepper process as locked-down as a renderer execpt that it can | 327 // The Pepper process as locked-down as a renderer execpt that it can |
| 313 // create the server side of chrome pipes. | 328 // create the server side of chrome pipes. |
| 314 bool AddPolicyForPepperPlugin(sandbox::TargetPolicy* policy) { | 329 bool AddPolicyForPepperPlugin(sandbox::TargetPolicy* policy) { |
| 315 sandbox::ResultCode result; | 330 sandbox::ResultCode result; |
| 316 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, | 331 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, |
| 317 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, | 332 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, |
| 318 L"\\\\.\\pipe\\chrome.*"); | 333 L"\\\\.\\pipe\\chrome.*"); |
| 319 if (result != sandbox::SBOX_ALL_OK) { | 334 if (result != sandbox::SBOX_ALL_OK) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 in_sandbox = true; | 441 in_sandbox = true; |
| 427 } | 442 } |
| 428 | 443 |
| 429 if (!in_sandbox) { | 444 if (!in_sandbox) { |
| 430 policy->Release(); | 445 policy->Release(); |
| 431 base::LaunchProcess(*cmd_line, base::LaunchOptions(), &process); | 446 base::LaunchProcess(*cmd_line, base::LaunchOptions(), &process); |
| 432 return process; | 447 return process; |
| 433 } | 448 } |
| 434 | 449 |
| 435 if (type == ChildProcessInfo::PLUGIN_PROCESS) { | 450 if (type == ChildProcessInfo::PLUGIN_PROCESS) { |
| 436 AddDllEvictionPolicy(policy); | 451 AddGenericDllEvictionPolicy(policy); |
| 452 AddPluginDllEvictionPolicy(policy); |
| 437 } else if (type == ChildProcessInfo::GPU_PROCESS) { | 453 } else if (type == ChildProcessInfo::GPU_PROCESS) { |
| 438 if (!AddPolicyForGPU(cmd_line, policy)) | 454 if (!AddPolicyForGPU(cmd_line, policy)) |
| 439 return 0; | 455 return 0; |
| 440 } else if (type == ChildProcessInfo::PPAPI_PLUGIN_PROCESS) { | 456 } else if (type == ChildProcessInfo::PPAPI_PLUGIN_PROCESS) { |
| 441 if (!AddPolicyForPepperPlugin(policy)) | 457 if (!AddPolicyForPepperPlugin(policy)) |
| 442 return 0; | 458 return 0; |
| 443 } else { | 459 } else { |
| 444 AddPolicyForRenderer(policy); | 460 AddPolicyForRenderer(policy); |
| 445 // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper. | 461 // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper. |
| 446 // Just have to figure out what needs to be warmed up first. | 462 // Just have to figure out what needs to be warmed up first. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 | 532 |
| 517 // Help the process a little. It can't start the debugger by itself if | 533 // Help the process a little. It can't start the debugger by itself if |
| 518 // the process is in a sandbox. | 534 // the process is in a sandbox. |
| 519 if (child_needs_help) | 535 if (child_needs_help) |
| 520 base::debug::SpawnDebuggerOnProcess(target.dwProcessId); | 536 base::debug::SpawnDebuggerOnProcess(target.dwProcessId); |
| 521 | 537 |
| 522 return process; | 538 return process; |
| 523 } | 539 } |
| 524 | 540 |
| 525 } // namespace sandbox | 541 } // namespace sandbox |
| OLD | NEW |