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 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
542 // Creates a temporary directory under |base_path| and returns the full path | 551 // Creates a temporary directory under |base_path| and returns the full path |
543 // of created directory in |work_dir|. If successful return true, otherwise | 552 // of created directory in |work_dir|. If successful return true, otherwise |
544 // false. When successful, the returned |work_dir| will always have a trailing | 553 // false. When successful, the returned |work_dir| will always have a trailing |
545 // backslash and this function requires that |base_path| always includes a | 554 // backslash and this function requires that |base_path| always includes a |
546 // trailing backslash as well. | 555 // trailing backslash as well. |
547 // We do not use GetTempFileName here to avoid running into AV software that | 556 // 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 | 557 // 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 | 558 // 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 | 559 // 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. | 560 // collision, we retry a few times with a new name before failing. |
552 bool CreateWorkDir(const wchar_t* base_path, PathString* work_dir) { | 561 bool CreateWorkDir(const wchar_t* base_path, PathString* work_dir) { |
grt (UTC plus 2)
2015/12/04 16:51:43
regarding testing, i think it's appropriate to mov
jschuh
2015/12/05 01:04:39
In principle I agree. In practice, this was how I
grt (UTC plus 2)
2015/12/07 14:56:22
sgtm provided that you satisfy my request below.
| |
553 if (!work_dir->assign(base_path) || !work_dir->append(kTempPrefix)) | 562 if (!work_dir->assign(base_path) || !work_dir->append(kTempPrefix)) |
554 return false; | 563 return false; |
555 | 564 |
556 // Store the location where we'll append the id. | 565 // Store the location where we'll append the id. |
557 size_t end = work_dir->length(); | 566 size_t end = work_dir->length(); |
558 | 567 |
559 // Check if we'll have enough buffer space to continue. | 568 // 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 | 569 // 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 | 570 // 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. | 571 // 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)) | 572 if ((work_dir->capacity() - end) < (_countof("fffff.tmp") + 1)) |
564 return false; | 573 return false; |
565 | 574 |
566 // Generate a unique id. We only use the lowest 20 bits, so take the top | 575 // Add an ACL if supported by the filesystem. Otherwise system-level installs |
567 // 12 bits and xor them with the lower bits. | 576 // are potentially vulnerable to file squatting attacks. |
568 DWORD id = ::GetTickCount(); | 577 SECURITY_ATTRIBUTES sa = {}; |
569 id ^= (id >> 12); | 578 sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
579 wchar_t volume[MAX_PATH]; | |
grt (UTC plus 2)
2015/12/04 15:37:35
use PathString here rather than a wchar_t array:
jschuh
2015/12/05 01:04:39
Done.
| |
580 DWORD flags = 0; | |
581 if (GetVolumePathName(base_path, volume, sizeof(volume)) && | |
582 GetVolumeInformation(volume, nullptr, 0, nullptr, nullptr, &flags, | |
grt (UTC plus 2)
2015/12/04 15:37:35
sadly, we can't use C++-11 yet in mini_installer s
jschuh
2015/12/05 01:04:39
Done.
| |
583 nullptr, 0) && | |
584 (flags & FILE_PERSISTENT_ACLS)) { | |
585 static const wchar_t sddl[] = | |
586 L"D:PAI(A;ID;FA;;;BA)" // Admin: Full control. | |
587 L"(A;OICIIOID;GA;;;BA)" | |
588 L"(A;ID;FA;;;SY)" // System: Full control. | |
589 L"(A;OICIIOID;GA;;;SY)" | |
590 L"(A;ID;FA;;;CO)" // Owner: Full control. | |
591 L"(A;OICIIOID;GA;;;CO)"; | |
592 if (!ConvertStringSecurityDescriptorToSecurityDescriptor( | |
593 sddl, SDDL_REVISION, &sa.lpSecurityDescriptor, NULL)) { | |
grt (UTC plus 2)
2015/12/04 15:37:35
is it safer to explicitly use SDDL_REVISION_1? MSD
jschuh
2015/12/05 01:04:39
Done.
| |
594 return false; | |
595 } | |
596 } | |
570 | 597 |
571 int max_attempts = 10; | 598 bool result = false; |
572 while (max_attempts--) { | 599 unsigned int id; |
600 RtlGenRandom(&id, sizeof(id)); | |
601 for (int max_attempts = 10; max_attempts; --max_attempts) { | |
573 // This converts 'id' to a string in the format "78563412" on windows | 602 // 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 | 603 // because of little endianness, but we don't care since it's just |
575 // a name. | 604 // a name. |
576 if (!HexEncode(&id, sizeof(id), work_dir->get() + end, | 605 if (!HexEncode(&id, sizeof(id), work_dir->get() + end, |
577 work_dir->capacity() - end)) { | 606 work_dir->capacity() - end)) { |
578 return false; | 607 break; |
579 } | 608 } |
580 | 609 |
581 // We only want the first 5 digits to remain within the 8.3 file name | 610 // We only want the first 5 digits to remain within the 8.3 file name |
582 // format (compliant with previous implementation). | 611 // format (compliant with previous implementation). |
583 work_dir->truncate_at(end + 5); | 612 work_dir->truncate_at(end + 5); |
584 | 613 |
585 // for consistency with the previous implementation which relied on | 614 // for consistency with the previous implementation which relied on |
586 // GetTempFileName, we append the .tmp extension. | 615 // GetTempFileName, we append the .tmp extension. |
587 work_dir->append(L".tmp"); | 616 work_dir->append(L".tmp"); |
588 if (::CreateDirectory(work_dir->get(), NULL)) { | 617 |
618 if (::CreateDirectory(work_dir->get(), | |
619 sa.lpSecurityDescriptor ? &sa : nullptr)) { | |
589 // Yay! Now let's just append the backslash and we're done. | 620 // Yay! Now let's just append the backslash and we're done. |
590 return work_dir->append(L"\\"); | 621 result = work_dir->append(L"\\"); |
622 break; | |
591 } | 623 } |
592 ++id; // Try a different name. | 624 ++id; // Try a different name. |
593 } | 625 } |
594 | 626 |
595 return false; | 627 if (sa.lpSecurityDescriptor) |
628 LocalFree(sa.lpSecurityDescriptor); | |
629 return result; | |
596 } | 630 } |
597 | 631 |
598 // Creates and returns a temporary directory in |work_dir| that can be used to | 632 // 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. | 633 // extract mini_installer payload. |work_dir| ends with a path separator. |
600 bool GetWorkDir(HMODULE module, PathString* work_dir) { | 634 bool GetWorkDir(HMODULE module, PathString* work_dir) { |
601 PathString base_path; | 635 PathString base_path; |
602 DWORD len = ::GetTempPath(static_cast<DWORD>(base_path.capacity()), | 636 DWORD len = ::GetTempPath(static_cast<DWORD>(base_path.capacity()), |
603 base_path.get()); | 637 base_path.get()); |
604 if (!len || len >= base_path.capacity() || | 638 if (!len || len >= base_path.capacity() || |
605 !CreateWorkDir(base_path.get(), work_dir)) { | 639 !CreateWorkDir(base_path.get(), work_dir)) { |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
834 #pragma function(memset) | 868 #pragma function(memset) |
835 void* memset(void* dest, int c, size_t count) { | 869 void* memset(void* dest, int c, size_t count) { |
836 void* start = dest; | 870 void* start = dest; |
837 while (count--) { | 871 while (count--) { |
838 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 872 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
839 dest = reinterpret_cast<char*>(dest) + 1; | 873 dest = reinterpret_cast<char*>(dest) + 1; |
840 } | 874 } |
841 return start; | 875 return start; |
842 } | 876 } |
843 } // extern "C" | 877 } // extern "C" |
OLD | NEW |