Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // mini_installer.exe is the first exe that is run when chrome is being | 5 // mini_installer.exe is the first exe that is run when chrome is being |
| 6 // installed or upgraded. It is designed to be extremely small (~5KB with no | 6 // installed or upgraded. It is designed to be extremely small (~5KB with no |
| 7 // extra resources linked) and it has two main jobs: | 7 // extra resources linked) and it has two main jobs: |
| 8 // 1) unpack the resources (possibly decompressing some) | 8 // 1) unpack the resources (possibly decompressing some) |
| 9 // 2) run the real installer (setup.exe) with appropriate flags. | 9 // 2) run the real installer (setup.exe) with appropriate flags. |
| 10 // | 10 // |
| 11 // In order to be really small the app doesn't link against the CRT and | 11 // In order to be really small the app doesn't link against the CRT and |
| 12 // defines the following compiler/linker flags: | 12 // defines the following compiler/linker flags: |
| 13 // EnableIntrinsicFunctions="true" compiler: /Oi | 13 // EnableIntrinsicFunctions="true" compiler: /Oi |
| 14 // BasicRuntimeChecks="0" | 14 // BasicRuntimeChecks="0" |
| 15 // BufferSecurityCheck="false" compiler: /GS- | 15 // BufferSecurityCheck="false" compiler: /GS- |
| 16 // EntryPointSymbol="MainEntryPoint" linker: /ENTRY | 16 // EntryPointSymbol="MainEntryPoint" linker: /ENTRY |
| 17 // IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB | 17 // IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB |
| 18 // OptimizeForWindows98="1" liker: /OPT:NOWIN98 | 18 // OptimizeForWindows98="1" liker: /OPT:NOWIN98 |
| 19 // linker: /SAFESEH:NO | 19 // linker: /SAFESEH:NO |
| 20 | 20 |
| 21 // have the linker merge the sections, saving us ~500 bytes. | 21 // have the linker merge the sections, saving us ~500 bytes. |
| 22 #pragma comment(linker, "/MERGE:.rdata=.text") | 22 #pragma comment(linker, "/MERGE:.rdata=.text") |
| 23 | 23 |
| 24 #include <windows.h> | 24 #include <windows.h> |
| 25 | |
| 26 // #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the | |
| 27 // "Community Additions" comment on MSDN here: | |
| 28 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx | |
| 29 #define SystemFunction036 NTAPI SystemFunction036 | |
| 30 #include <NTSecAPI.h> | |
| 31 #undef SystemFunction036 | |
| 32 | |
| 33 #include <sddl.h> | |
| 25 #include <shellapi.h> | 34 #include <shellapi.h> |
| 26 #include <stdlib.h> | 35 #include <stdlib.h> |
| 27 | 36 |
| 28 #include "chrome/installer/mini_installer/appid.h" | 37 #include "chrome/installer/mini_installer/appid.h" |
| 29 #include "chrome/installer/mini_installer/configuration.h" | 38 #include "chrome/installer/mini_installer/configuration.h" |
| 30 #include "chrome/installer/mini_installer/decompress.h" | 39 #include "chrome/installer/mini_installer/decompress.h" |
| 31 #include "chrome/installer/mini_installer/exit_code.h" | 40 #include "chrome/installer/mini_installer/exit_code.h" |
| 32 #include "chrome/installer/mini_installer/mini_installer_constants.h" | 41 #include "chrome/installer/mini_installer/mini_installer_constants.h" |
| 33 #include "chrome/installer/mini_installer/mini_string.h" | 42 #include "chrome/installer/mini_installer/mini_string.h" |
| 34 #include "chrome/installer/mini_installer/pe_resource.h" | 43 #include "chrome/installer/mini_installer/pe_resource.h" |
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 532 // Deletes given files and working dir. | 541 // Deletes given files and working dir. |
| 533 void DeleteExtractedFiles(const wchar_t* base_path, | 542 void DeleteExtractedFiles(const wchar_t* base_path, |
| 534 const wchar_t* archive_path, | 543 const wchar_t* archive_path, |
| 535 const wchar_t* setup_path) { | 544 const wchar_t* setup_path) { |
| 536 ::DeleteFile(archive_path); | 545 ::DeleteFile(archive_path); |
| 537 ::DeleteFile(setup_path); | 546 ::DeleteFile(setup_path); |
| 538 // Delete the temp dir (if it is empty, otherwise fail). | 547 // Delete the temp dir (if it is empty, otherwise fail). |
| 539 ::RemoveDirectory(base_path); | 548 ::RemoveDirectory(base_path); |
| 540 } | 549 } |
| 541 | 550 |
| 551 // Returns true if the supplied path supports ACLs. | |
| 552 bool IsAclSupportedForPath(const wchar_t* path) { | |
| 553 PathString volume; | |
| 554 DWORD flags = 0; | |
| 555 return ::GetVolumePathName(path, volume.get(), volume.capacity()) && | |
| 556 ::GetVolumeInformation(volume.get(), NULL, 0, NULL, NULL, &flags, NULL, | |
|
grt (UTC plus 2)
2015/12/07 14:56:23
did "git cl format" do this indentation? i would e
jschuh
2015/12/11 04:07:24
VS keeps trying to cleverly reformat things after
| |
| 557 0) || (flags & FILE_PERSISTENT_ACLS); | |
|
grt (UTC plus 2)
2015/12/07 14:56:23
|| -> &&
jschuh
2015/12/11 04:07:24
Done. Forgot to reverse all the conditionals when
| |
| 558 } | |
| 559 | |
| 560 // Retrieves the SID of the default owner for objects created by this user | |
| 561 // token (accounting for different behavior under UAC elevation, etc.). | |
| 562 // NOTE: On success the |sid| parameter must be freed with LocalFree(). | |
| 563 bool GetCurrentOwnerSid(wchar_t** sid) { | |
| 564 HANDLE token; | |
| 565 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) | |
| 566 return false; | |
| 567 | |
| 568 DWORD size = 0; | |
| 569 TOKEN_OWNER* owner = NULL; | |
| 570 bool result = false; | |
| 571 // We get the TokenOwner rather than the TokenUser because e.g. under UAC | |
| 572 // elevation we want the admin to own the directory rather than the user. | |
| 573 ::GetTokenInformation(token, TokenOwner, &owner, 0, &size); | |
| 574 if (size && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | |
| 575 if (owner = reinterpret_cast<TOKEN_OWNER*>(::LocalAlloc(LPTR, size))) { | |
| 576 if (GetTokenInformation(token, TokenOwner, owner, size, &size)) | |
|
grt (UTC plus 2)
2015/12/07 14:56:23
nit: ::GetTokenInformation
jschuh
2015/12/11 04:07:24
Done.
| |
| 577 result = ::ConvertSidToStringSid(owner->Owner, sid); | |
| 578 ::LocalFree(owner); | |
| 579 } | |
| 580 } | |
| 581 ::CloseHandle(token); | |
| 582 return result; | |
| 583 } | |
| 584 | |
| 585 // Sets an ACL allowing only the current owner, admin, and system. | |
|
grt (UTC plus 2)
2015/12/07 14:56:22
suggested comment (assuming it's correct):
// Popu
jschuh
2015/12/11 04:07:24
Done.
| |
| 586 // NOTE: On success the |sd| parameter must be freed with LocalFree(). | |
| 587 bool SetSecurityDescriptor(PSECURITY_DESCRIPTOR* sd, const wchar_t* path) { | |
|
grt (UTC plus 2)
2015/12/07 14:56:22
swap sd and path since in params should precede ou
jschuh
2015/12/11 04:07:24
Done.
| |
| 588 *sd = NULL; | |
| 589 if (!IsAclSupportedForPath(path)) | |
| 590 return true; | |
| 591 | |
| 592 wchar_t* sid = NULL; | |
| 593 if (!GetCurrentOwnerSid(&sid)) | |
| 594 return false; | |
| 595 | |
| 596 // The largest SID is under 200 characters, so 300 should give enough slack. | |
| 597 StackString<300> sddl; | |
| 598 bool result = sddl.append(L"D:PAI(A;ID;FA;;;BA)" // Admin: Full control. | |
|
grt (UTC plus 2)
2015/12/07 14:56:22
nit: break this line just before the open paren so
grt (UTC plus 2)
2015/12/07 14:56:23
i think the "ID" flag should be removed here and b
grt (UTC plus 2)
2015/12/07 14:56:23
to be utterly pedantic, each of these should have
jschuh
2015/12/11 04:07:24
D'oh. cargo cult. Done.
jschuh
2015/12/11 04:07:24
Done.
jschuh
2015/12/11 04:07:24
The documentation is a lie! At least, it went all
grt (UTC plus 2)
2015/12/14 18:59:26
Ah, I meant like this:
bool result = sddl.append
jschuh
2015/12/15 20:58:58
I've now adjusted the first line, but I think it m
| |
| 599 L"(A;OICIIOID;GA;;;BA)" | |
|
grt (UTC plus 2)
2015/12/07 14:56:22
nit: each of these should be four-space indented
grt (UTC plus 2)
2015/12/07 14:56:23
IIUC:
OI - files in this directory will inherit th
jschuh
2015/12/11 04:07:24
Oops. My brain keeps thinking "temp directory" rat
jschuh
2015/12/11 04:07:24
"Visual Studio!!!!!!!"
grt (UTC plus 2)
2015/12/14 18:59:26
Give up and use a real editor. :-)
| |
| 600 L"(A;ID;FA;;;SY)" // System: Full control. | |
| 601 L"(A;OICIIOID;GA;;;SY)" | |
| 602 L"(A;OICIIOID;GA;;;CO)" // Owner: Full control. | |
| 603 L"(A;ID;FA;;;") && | |
| 604 sddl.append(sid) && sddl.append(L")"); | |
| 605 | |
| 606 if (result) { | |
| 607 result = ::ConvertStringSecurityDescriptorToSecurityDescriptor(sddl.get(), | |
| 608 SDDL_REVISION_1, sd, NULL); | |
| 609 } | |
| 610 | |
| 611 ::LocalFree(sid); | |
| 612 return result; | |
| 613 } | |
| 614 | |
| 542 // Creates a temporary directory under |base_path| and returns the full path | 615 // Creates a temporary directory under |base_path| and returns the full path |
| 543 // of created directory in |work_dir|. If successful return true, otherwise | 616 // of created directory in |work_dir|. If successful return true, otherwise |
| 544 // false. When successful, the returned |work_dir| will always have a trailing | 617 // false. When successful, the returned |work_dir| will always have a trailing |
| 545 // backslash and this function requires that |base_path| always includes a | 618 // backslash and this function requires that |base_path| always includes a |
| 546 // trailing backslash as well. | 619 // trailing backslash as well. |
| 547 // We do not use GetTempFileName here to avoid running into AV software that | 620 // We do not use GetTempFileName here to avoid running into AV software that |
| 548 // might hold on to the temp file as soon as we create it and then we can't | 621 // might hold on to the temp file as soon as we create it and then we can't |
| 549 // delete it and create a directory in its place. So, we use our own mechanism | 622 // delete it and create a directory in its place. So, we use our own mechanism |
| 550 // for creating a directory with a hopefully-unique name. In the case of a | 623 // for creating a directory with a hopefully-unique name. In the case of a |
| 551 // collision, we retry a few times with a new name before failing. | 624 // collision, we retry a few times with a new name before failing. |
| 552 bool CreateWorkDir(const wchar_t* base_path, PathString* work_dir) { | 625 bool CreateWorkDir(const wchar_t* base_path, PathString* work_dir) { |
| 553 if (!work_dir->assign(base_path) || !work_dir->append(kTempPrefix)) | 626 if (!work_dir->assign(base_path) || !work_dir->append(kTempPrefix)) |
| 554 return false; | 627 return false; |
| 555 | 628 |
| 556 // Store the location where we'll append the id. | 629 // Store the location where we'll append the id. |
| 557 size_t end = work_dir->length(); | 630 size_t end = work_dir->length(); |
| 558 | 631 |
| 559 // Check if we'll have enough buffer space to continue. | 632 // Check if we'll have enough buffer space to continue. |
| 560 // The name of the directory will use up 11 chars and then we need to append | 633 // The name of the directory will use up 11 chars and then we need to append |
| 561 // the trailing backslash and a terminator. We've already added the prefix | 634 // the trailing backslash and a terminator. We've already added the prefix |
| 562 // to the buffer, so let's just make sure we've got enough space for the rest. | 635 // to the buffer, so let's just make sure we've got enough space for the rest. |
| 563 if ((work_dir->capacity() - end) < (_countof("fffff.tmp") + 1)) | 636 if ((work_dir->capacity() - end) < (_countof("fffff.tmp") + 1)) |
| 564 return false; | 637 return false; |
| 565 | 638 |
| 566 // Generate a unique id. We only use the lowest 20 bits, so take the top | 639 // Add an ACL if supported by the filesystem. Otherwise system-level installs |
| 567 // 12 bits and xor them with the lower bits. | 640 // are potentially vulnerable to file squatting attacks. |
| 568 DWORD id = ::GetTickCount(); | 641 SECURITY_ATTRIBUTES sa = {}; |
| 569 id ^= (id >> 12); | 642 sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
| 643 if (!SetSecurityDescriptor(&sa.lpSecurityDescriptor, base_path)) | |
| 644 return false; | |
| 570 | 645 |
| 571 int max_attempts = 10; | 646 unsigned int id; |
| 572 while (max_attempts--) { | 647 RtlGenRandom(&id, sizeof(id)); |
|
grt (UTC plus 2)
2015/12/07 14:56:23
nit: ::RtlGenRandom
jschuh
2015/12/11 04:07:24
Done.
| |
| 648 bool result = false; | |
| 649 for (int max_attempts = 10; max_attempts; --max_attempts) { | |
| 573 // This converts 'id' to a string in the format "78563412" on windows | 650 // This converts 'id' to a string in the format "78563412" on windows |
| 574 // because of little endianness, but we don't care since it's just | 651 // because of little endianness, but we don't care since it's just |
| 575 // a name. | 652 // a name. |
| 576 if (!HexEncode(&id, sizeof(id), work_dir->get() + end, | 653 if (!HexEncode(&id, sizeof(id), work_dir->get() + end, |
| 577 work_dir->capacity() - end)) { | 654 work_dir->capacity() - end)) { |
| 578 return false; | 655 break; |
| 579 } | 656 } |
| 580 | 657 |
| 581 // We only want the first 5 digits to remain within the 8.3 file name | 658 // We only want the first 5 digits to remain within the 8.3 file name |
| 582 // format (compliant with previous implementation). | 659 // format (compliant with previous implementation). |
| 583 work_dir->truncate_at(end + 5); | 660 work_dir->truncate_at(end + 5); |
| 584 | 661 |
| 585 // for consistency with the previous implementation which relied on | 662 // for consistency with the previous implementation which relied on |
| 586 // GetTempFileName, we append the .tmp extension. | 663 // GetTempFileName, we append the .tmp extension. |
| 587 work_dir->append(L".tmp"); | 664 work_dir->append(L".tmp"); |
| 588 if (::CreateDirectory(work_dir->get(), NULL)) { | 665 |
| 666 if (::CreateDirectory(work_dir->get(), | |
| 667 sa.lpSecurityDescriptor ? &sa : NULL)) { | |
| 589 // Yay! Now let's just append the backslash and we're done. | 668 // Yay! Now let's just append the backslash and we're done. |
| 590 return work_dir->append(L"\\"); | 669 result = work_dir->append(L"\\"); |
| 670 break; | |
| 591 } | 671 } |
| 592 ++id; // Try a different name. | 672 ++id; // Try a different name. |
| 593 } | 673 } |
| 594 | 674 |
| 595 return false; | 675 if (sa.lpSecurityDescriptor) |
| 676 LocalFree(sa.lpSecurityDescriptor); | |
| 677 return result; | |
| 596 } | 678 } |
| 597 | 679 |
| 598 // Creates and returns a temporary directory in |work_dir| that can be used to | 680 // Creates and returns a temporary directory in |work_dir| that can be used to |
| 599 // extract mini_installer payload. |work_dir| ends with a path separator. | 681 // extract mini_installer payload. |work_dir| ends with a path separator. |
| 600 bool GetWorkDir(HMODULE module, PathString* work_dir) { | 682 bool GetWorkDir(HMODULE module, PathString* work_dir) { |
| 601 PathString base_path; | 683 PathString base_path; |
| 602 DWORD len = ::GetTempPath(static_cast<DWORD>(base_path.capacity()), | 684 DWORD len = ::GetTempPath(static_cast<DWORD>(base_path.capacity()), |
| 603 base_path.get()); | 685 base_path.get()); |
| 604 if (!len || len >= base_path.capacity() || | 686 if (!len || len >= base_path.capacity() || |
| 605 !CreateWorkDir(base_path.get(), work_dir)) { | 687 !CreateWorkDir(base_path.get(), work_dir)) { |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 834 #pragma function(memset) | 916 #pragma function(memset) |
| 835 void* memset(void* dest, int c, size_t count) { | 917 void* memset(void* dest, int c, size_t count) { |
| 836 void* start = dest; | 918 void* start = dest; |
| 837 while (count--) { | 919 while (count--) { |
| 838 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 920 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
| 839 dest = reinterpret_cast<char*>(dest) + 1; | 921 dest = reinterpret_cast<char*>(dest) + 1; |
| 840 } | 922 } |
| 841 return start; | 923 return start; |
| 842 } | 924 } |
| 843 } // extern "C" | 925 } // extern "C" |
| OLD | NEW |