diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2021-05-03 12:23:31 -0500 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2021-05-11 19:11:19 -0500 |
commit | cd921db764df9578733c85c29e8c6c368f4c7e78 (patch) | |
tree | 8c04087da4430101afa9c065cc5c6555335d4b32 | |
parent | 67dd3ced3b383eb8423156cdabd3f9ce037caba8 (diff) | |
download | wix-cd921db764df9578733c85c29e8c6c368f4c7e78.tar.gz wix-cd921db764df9578733c85c29e8c6c368f4c7e78.tar.bz2 wix-cd921db764df9578733c85c29e8c6c368f4c7e78.zip |
Enforce payload and container verification.
-rw-r--r-- | src/burn/engine/apply.cpp | 4 | ||||
-rw-r--r-- | src/burn/engine/cache.cpp | 95 | ||||
-rw-r--r-- | src/burn/engine/container.cpp | 50 | ||||
-rw-r--r-- | src/burn/engine/container.h | 8 | ||||
-rw-r--r-- | src/burn/engine/payload.cpp | 127 | ||||
-rw-r--r-- | src/burn/engine/payload.h | 8 | ||||
-rw-r--r-- | src/burn/engine/pseudobundle.cpp | 5 | ||||
-rw-r--r-- | src/burn/test/BurnUnitTest/CacheTest.cpp | 2 | ||||
-rw-r--r-- | src/burn/test/BurnUnitTest/PlanTest.cpp | 2 |
9 files changed, 209 insertions, 92 deletions
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index b4fa9dac..4d527409 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp | |||
@@ -1410,12 +1410,12 @@ static HRESULT AcquireContainerOrPayload( | |||
1410 | fMinimumFileSize = TRUE; | 1410 | fMinimumFileSize = TRUE; |
1411 | qwFileSize = pContainer->qwAttachedOffset + pContainer->qwFileSize; | 1411 | qwFileSize = pContainer->qwAttachedOffset + pContainer->qwFileSize; |
1412 | } | 1412 | } |
1413 | else if (pContainer->pbHash && pContext->wzLayoutDirectory) | 1413 | else |
1414 | { | 1414 | { |
1415 | qwFileSize = pContainer->qwFileSize; | 1415 | qwFileSize = pContainer->qwFileSize; |
1416 | } | 1416 | } |
1417 | } | 1417 | } |
1418 | else if (pPayload->pbHash) | 1418 | else if (BURN_PAYLOAD_VERIFICATION_HASH == pPayload->verification || BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE == pPayload->verification) |
1419 | { | 1419 | { |
1420 | qwFileSize = pPayload->qwFileSize; | 1420 | qwFileSize = pPayload->qwFileSize; |
1421 | } | 1421 | } |
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index 02cad4a5..44267cbc 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp | |||
@@ -114,10 +114,16 @@ static HRESULT RemoveBundleOrPackage( | |||
114 | __in_z LPCWSTR wzBundleOrPackageId, | 114 | __in_z LPCWSTR wzBundleOrPackageId, |
115 | __in_z LPCWSTR wzCacheId | 115 | __in_z LPCWSTR wzCacheId |
116 | ); | 116 | ); |
117 | static HRESULT VerifyFileSize( | ||
118 | __in HANDLE hFile, | ||
119 | __in DWORD64 qwFileSize, | ||
120 | __in_z LPCWSTR wzUnverifiedPayloadPath | ||
121 | ); | ||
117 | static HRESULT VerifyHash( | 122 | static HRESULT VerifyHash( |
118 | __in BYTE* pbHash, | 123 | __in BYTE* pbHash, |
119 | __in DWORD cbHash, | 124 | __in DWORD cbHash, |
120 | __in DWORD64 qwFileSize, | 125 | __in DWORD64 qwFileSize, |
126 | __in BOOL fVerifyFileSize, | ||
121 | __in_z LPCWSTR wzUnverifiedPayloadPath, | 127 | __in_z LPCWSTR wzUnverifiedPayloadPath, |
122 | __in HANDLE hFile, | 128 | __in HANDLE hFile, |
123 | __in BURN_CACHE_STEP cacheStep, | 129 | __in BURN_CACHE_STEP cacheStep, |
@@ -1513,11 +1519,16 @@ static HRESULT VerifyThenTransferContainer( | |||
1513 | ExitWithLastError(hr, "Failed to open container in working path: %ls", wzUnverifiedContainerPath); | 1519 | ExitWithLastError(hr, "Failed to open container in working path: %ls", wzUnverifiedContainerPath); |
1514 | } | 1520 | } |
1515 | 1521 | ||
1516 | // Container should have a hash we can use to verify with. | 1522 | |
1517 | if (pContainer->pbHash) | 1523 | switch (pContainer->verification) |
1518 | { | 1524 | { |
1519 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, wzUnverifiedContainerPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | 1525 | case BURN_CONTAINER_VERIFICATION_HASH: |
1526 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, TRUE, wzUnverifiedContainerPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | ||
1520 | ExitOnFailure(hr, "Failed to verify container hash: %ls", wzCachedPath); | 1527 | ExitOnFailure(hr, "Failed to verify container hash: %ls", wzCachedPath); |
1528 | break; | ||
1529 | default: | ||
1530 | ExitOnRootFailure(hr = E_INVALIDARG, "Container has no verification information: %ls", pContainer->sczId); | ||
1531 | break; | ||
1521 | } | 1532 | } |
1522 | 1533 | ||
1523 | LogStringLine(REPORT_STANDARD, "%ls container from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedContainerPath, wzCachedPath); | 1534 | LogStringLine(REPORT_STANDARD, "%ls container from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedContainerPath, wzCachedPath); |
@@ -1550,10 +1561,16 @@ static HRESULT VerifyThenTransferPayload( | |||
1550 | ExitWithLastError(hr, "Failed to open payload in working path: %ls", wzUnverifiedPayloadPath); | 1561 | ExitWithLastError(hr, "Failed to open payload in working path: %ls", wzUnverifiedPayloadPath); |
1551 | } | 1562 | } |
1552 | 1563 | ||
1553 | if (pPayload->pbHash) // the payload should have a hash we can use to verify it. | 1564 | switch (pPayload->verification) |
1554 | { | 1565 | { |
1555 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, wzUnverifiedPayloadPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | 1566 | case BURN_PAYLOAD_VERIFICATION_HASH: |
1567 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, TRUE, wzUnverifiedPayloadPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); | ||
1556 | ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath); | 1568 | ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath); |
1569 | break; | ||
1570 | case BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE: __fallthrough; | ||
1571 | default: | ||
1572 | ExitOnRootFailure(hr = E_INVALIDARG, "Payload has no verification information: %ls", pPayload->sczKey); | ||
1573 | break; | ||
1557 | } | 1574 | } |
1558 | 1575 | ||
1559 | LogStringLine(REPORT_STANDARD, "%ls payload from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedPayloadPath, wzCachedPath); | 1576 | LogStringLine(REPORT_STANDARD, "%ls payload from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedPayloadPath, wzCachedPath); |
@@ -1627,10 +1644,15 @@ static HRESULT VerifyFileAgainstContainer( | |||
1627 | ExitOnRootFailure(hr, "Failed to open container at path: %ls", wzVerifyPath); | 1644 | ExitOnRootFailure(hr, "Failed to open container at path: %ls", wzVerifyPath); |
1628 | } | 1645 | } |
1629 | 1646 | ||
1630 | if (pContainer->pbHash) // the container should have a hash we can use to verify it. | 1647 | switch (pContainer->verification) |
1631 | { | 1648 | { |
1632 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | 1649 | case BURN_CONTAINER_VERIFICATION_HASH: |
1650 | hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, TRUE, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | ||
1633 | ExitOnFailure(hr, "Failed to verify hash of container: %ls", pContainer->sczId); | 1651 | ExitOnFailure(hr, "Failed to verify hash of container: %ls", pContainer->sczId); |
1652 | break; | ||
1653 | default: | ||
1654 | ExitOnRootFailure(hr = E_INVALIDARG, "Container has no verification information: %ls", pContainer->sczId); | ||
1655 | break; | ||
1634 | } | 1656 | } |
1635 | 1657 | ||
1636 | if (fAlreadyCached) | 1658 | if (fAlreadyCached) |
@@ -1667,6 +1689,7 @@ static HRESULT VerifyFileAgainstPayload( | |||
1667 | { | 1689 | { |
1668 | HRESULT hr = S_OK; | 1690 | HRESULT hr = S_OK; |
1669 | HANDLE hFile = INVALID_HANDLE_VALUE; | 1691 | HANDLE hFile = INVALID_HANDLE_VALUE; |
1692 | BOOL fVerifyFileSize = FALSE; | ||
1670 | 1693 | ||
1671 | // Get the payload on disk actual hash. | 1694 | // Get the payload on disk actual hash. |
1672 | hFile = ::CreateFileW(wzVerifyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | 1695 | hFile = ::CreateFileW(wzVerifyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); |
@@ -1680,10 +1703,33 @@ static HRESULT VerifyFileAgainstPayload( | |||
1680 | ExitOnRootFailure(hr, "Failed to open payload at path: %ls", wzVerifyPath); | 1703 | ExitOnRootFailure(hr, "Failed to open payload at path: %ls", wzVerifyPath); |
1681 | } | 1704 | } |
1682 | 1705 | ||
1683 | if (pPayload->pbHash) // the payload should have a hash we can use to verify it. | 1706 | switch (pPayload->verification) |
1684 | { | 1707 | { |
1685 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | 1708 | case BURN_PAYLOAD_VERIFICATION_HASH: |
1709 | fVerifyFileSize = TRUE; | ||
1710 | |||
1711 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, fVerifyFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | ||
1686 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); | 1712 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); |
1713 | |||
1714 | break; | ||
1715 | case BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE: | ||
1716 | fVerifyFileSize = 0 != pPayload->qwFileSize; | ||
1717 | |||
1718 | if (pPayload->pbHash) | ||
1719 | { | ||
1720 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, fVerifyFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext); | ||
1721 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); | ||
1722 | } | ||
1723 | else if (fVerifyFileSize) | ||
1724 | { | ||
1725 | hr = VerifyFileSize(hFile, pPayload->qwFileSize, wzVerifyPath); | ||
1726 | ExitOnFailure(hr, "Failed to verify file size for path: %ls", wzVerifyPath); | ||
1727 | } | ||
1728 | |||
1729 | break; | ||
1730 | default: | ||
1731 | ExitOnRootFailure(hr = E_INVALIDARG, "Payload has no verification information: %ls", pPayload->sczKey); | ||
1732 | break; | ||
1687 | } | 1733 | } |
1688 | 1734 | ||
1689 | if (fAlreadyCached) | 1735 | if (fAlreadyCached) |
@@ -2015,10 +2061,32 @@ LExit: | |||
2015 | return hr; | 2061 | return hr; |
2016 | } | 2062 | } |
2017 | 2063 | ||
2064 | static HRESULT VerifyFileSize( | ||
2065 | __in HANDLE hFile, | ||
2066 | __in DWORD64 qwFileSize, | ||
2067 | __in_z LPCWSTR wzUnverifiedPayloadPath | ||
2068 | ) | ||
2069 | { | ||
2070 | HRESULT hr = S_OK; | ||
2071 | LONGLONG llSize = 0; | ||
2072 | |||
2073 | hr = FileSizeByHandle(hFile, &llSize); | ||
2074 | ExitOnFailure(hr, "Failed to get file size for path: %ls", wzUnverifiedPayloadPath); | ||
2075 | |||
2076 | if (static_cast<DWORD64>(llSize) != qwFileSize) | ||
2077 | { | ||
2078 | ExitOnRootFailure(hr = ERROR_FILE_CORRUPT, "File size mismatch for path: %ls, expected: %llu, actual: %lld", wzUnverifiedPayloadPath, qwFileSize, llSize); | ||
2079 | } | ||
2080 | |||
2081 | LExit: | ||
2082 | return hr; | ||
2083 | } | ||
2084 | |||
2018 | static HRESULT VerifyHash( | 2085 | static HRESULT VerifyHash( |
2019 | __in BYTE* pbHash, | 2086 | __in BYTE* pbHash, |
2020 | __in DWORD cbHash, | 2087 | __in DWORD cbHash, |
2021 | __in DWORD64 qwFileSize, | 2088 | __in DWORD64 qwFileSize, |
2089 | __in BOOL fVerifyFileSize, | ||
2022 | __in_z LPCWSTR wzUnverifiedPayloadPath, | 2090 | __in_z LPCWSTR wzUnverifiedPayloadPath, |
2023 | __in HANDLE hFile, | 2091 | __in HANDLE hFile, |
2024 | __in BURN_CACHE_STEP cacheStep, | 2092 | __in BURN_CACHE_STEP cacheStep, |
@@ -2032,19 +2100,16 @@ static HRESULT VerifyHash( | |||
2032 | HRESULT hr = S_OK; | 2100 | HRESULT hr = S_OK; |
2033 | BYTE rgbActualHash[SHA512_HASH_LEN] = { }; | 2101 | BYTE rgbActualHash[SHA512_HASH_LEN] = { }; |
2034 | DWORD64 qwHashedBytes = 0; | 2102 | DWORD64 qwHashedBytes = 0; |
2035 | LONGLONG llSize = 0; | ||
2036 | LPWSTR pszExpected = NULL; | 2103 | LPWSTR pszExpected = NULL; |
2037 | LPWSTR pszActual = NULL; | 2104 | LPWSTR pszActual = NULL; |
2038 | 2105 | ||
2039 | hr = SendCacheBeginMessage(pfnCacheMessageHandler, pContext, cacheStep); | 2106 | hr = SendCacheBeginMessage(pfnCacheMessageHandler, pContext, cacheStep); |
2040 | ExitOnFailure(hr, "Aborted cache verify hash begin."); | 2107 | ExitOnFailure(hr, "Aborted cache verify hash begin."); |
2041 | 2108 | ||
2042 | hr = FileSizeByHandle(hFile, &llSize); | 2109 | if (fVerifyFileSize) |
2043 | ExitOnFailure(hr, "Failed to get file size for path: %ls", wzUnverifiedPayloadPath); | ||
2044 | |||
2045 | if (static_cast<DWORD64>(llSize) != qwFileSize) | ||
2046 | { | 2110 | { |
2047 | ExitOnFailure(hr = ERROR_FILE_CORRUPT, "File size mismatch for path: %ls, expected: %llu, actual: %lld", wzUnverifiedPayloadPath, qwFileSize, llSize); | 2111 | hr = VerifyFileSize(hFile, qwFileSize, wzUnverifiedPayloadPath); |
2112 | ExitOnFailure(hr, "Failed to verify file size for path: %ls", wzUnverifiedPayloadPath); | ||
2048 | } | 2113 | } |
2049 | 2114 | ||
2050 | // TODO: create a cryp hash file that sends progress. | 2115 | // TODO: create a cryp hash file that sends progress. |
diff --git a/src/burn/engine/container.cpp b/src/burn/engine/container.cpp index 0cce3131..c6f2ada8 100644 --- a/src/burn/engine/container.cpp +++ b/src/burn/engine/container.cpp | |||
@@ -50,16 +50,9 @@ extern "C" HRESULT ContainersParseFromXml( | |||
50 | hr = XmlGetAttributeEx(pixnNode, L"Id", &pContainer->sczId); | 50 | hr = XmlGetAttributeEx(pixnNode, L"Id", &pContainer->sczId); |
51 | ExitOnFailure(hr, "Failed to get @Id."); | 51 | ExitOnFailure(hr, "Failed to get @Id."); |
52 | 52 | ||
53 | // @Primary | ||
54 | hr = XmlGetYesNoAttribute(pixnNode, L"Primary", &pContainer->fPrimary); | ||
55 | if (E_NOTFOUND != hr) | ||
56 | { | ||
57 | ExitOnFailure(hr, "Failed to get @Primary."); | ||
58 | } | ||
59 | |||
60 | // @Attached | 53 | // @Attached |
61 | hr = XmlGetYesNoAttribute(pixnNode, L"Attached", &pContainer->fAttached); | 54 | hr = XmlGetYesNoAttribute(pixnNode, L"Attached", &pContainer->fAttached); |
62 | if (E_NOTFOUND != hr || pContainer->fPrimary) // if it is a primary container, it has to be attached | 55 | if (E_NOTFOUND != hr) |
63 | { | 56 | { |
64 | ExitOnFailure(hr, "Failed to get @Attached."); | 57 | ExitOnFailure(hr, "Failed to get @Attached."); |
65 | } | 58 | } |
@@ -87,10 +80,7 @@ extern "C" HRESULT ContainersParseFromXml( | |||
87 | { | 80 | { |
88 | // @FilePath | 81 | // @FilePath |
89 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pContainer->sczFilePath); | 82 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pContainer->sczFilePath); |
90 | if (E_NOTFOUND != hr) | 83 | ExitOnFailure(hr, "Failed to get @FilePath."); |
91 | { | ||
92 | ExitOnFailure(hr, "Failed to get @FilePath."); | ||
93 | } | ||
94 | } | 84 | } |
95 | 85 | ||
96 | // The source path starts as the file path. | 86 | // The source path starts as the file path. |
@@ -99,23 +89,32 @@ extern "C" HRESULT ContainersParseFromXml( | |||
99 | 89 | ||
100 | // @DownloadUrl | 90 | // @DownloadUrl |
101 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pContainer->downloadSource.sczUrl); | 91 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pContainer->downloadSource.sczUrl); |
102 | if (E_NOTFOUND != hr || (!pContainer->fPrimary && !pContainer->sczSourcePath)) // if the package is not a primary package, it must have a source path or a download url | 92 | if (E_NOTFOUND != hr) |
103 | { | 93 | { |
104 | ExitOnFailure(hr, "Failed to get @DownloadUrl. Either @SourcePath or @DownloadUrl needs to be provided."); | 94 | ExitOnFailure(hr, "Failed to get @DownloadUrl."); |
105 | } | 95 | } |
106 | 96 | ||
107 | // @Hash | 97 | // @Hash |
108 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &pContainer->sczHash); | 98 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &pContainer->sczHash); |
109 | if (SUCCEEDED(hr)) | 99 | ExitOnFailure(hr, "Failed to get @Hash."); |
110 | { | 100 | |
111 | hr = StrAllocHexDecode(pContainer->sczHash, &pContainer->pbHash, &pContainer->cbHash); | 101 | hr = StrAllocHexDecode(pContainer->sczHash, &pContainer->pbHash, &pContainer->cbHash); |
112 | ExitOnFailure(hr, "Failed to hex decode the Container/@Hash."); | 102 | ExitOnFailure(hr, "Failed to hex decode the Container/@Hash."); |
113 | } | 103 | |
114 | else if (E_NOTFOUND != hr) | 104 | // @FileSize |
105 | hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz); | ||
106 | ExitOnFailure(hr, "Failed to get @FileSize."); | ||
107 | |||
108 | hr = StrStringToUInt64(scz, 0, &pContainer->qwFileSize); | ||
109 | ExitOnFailure(hr, "Failed to parse @FileSize."); | ||
110 | |||
111 | if (!pContainer->qwFileSize) | ||
115 | { | 112 | { |
116 | ExitOnFailure(hr, "Failed to get @Hash."); | 113 | ExitOnRootFailure(hr = E_INVALIDDATA, "File size is required when verifying by hash for container: %ls", pContainer->sczId); |
117 | } | 114 | } |
118 | 115 | ||
116 | pContainer->verification = BURN_CONTAINER_VERIFICATION_HASH; | ||
117 | |||
119 | // prepare next iteration | 118 | // prepare next iteration |
120 | ReleaseNullObject(pixnNode); | 119 | ReleaseNullObject(pixnNode); |
121 | } | 120 | } |
@@ -136,6 +135,7 @@ extern "C" HRESULT ContainersInitialize( | |||
136 | ) | 135 | ) |
137 | { | 136 | { |
138 | HRESULT hr = S_OK; | 137 | HRESULT hr = S_OK; |
138 | DWORD64 qwSize = 0; | ||
139 | 139 | ||
140 | if (pContainers->rgContainers) | 140 | if (pContainers->rgContainers) |
141 | { | 141 | { |
@@ -147,8 +147,13 @@ extern "C" HRESULT ContainersInitialize( | |||
147 | // manifest contained and get the offset to the container. | 147 | // manifest contained and get the offset to the container. |
148 | if (pContainer->fAttached) | 148 | if (pContainer->fAttached) |
149 | { | 149 | { |
150 | hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &pContainer->qwFileSize, &pContainer->fActuallyAttached); | 150 | hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &qwSize, &pContainer->fActuallyAttached); |
151 | ExitOnFailure(hr, "Failed to get attached container information."); | 151 | ExitOnFailure(hr, "Failed to get attached container information."); |
152 | |||
153 | if (qwSize != pContainer->qwFileSize) | ||
154 | { | ||
155 | ExitOnFailure(hr, "Attached container '%ls' size '%llu' didn't match size from manifest: '%llu'", pContainer->sczId, qwSize, pContainer->qwFileSize); | ||
156 | } | ||
152 | } | 157 | } |
153 | } | 158 | } |
154 | } | 159 | } |
@@ -195,7 +200,6 @@ extern "C" HRESULT ContainerOpenUX( | |||
195 | 200 | ||
196 | // open attached container | 201 | // open attached container |
197 | container.type = BURN_CONTAINER_TYPE_CABINET; | 202 | container.type = BURN_CONTAINER_TYPE_CABINET; |
198 | container.fPrimary = TRUE; | ||
199 | container.fAttached = TRUE; | 203 | container.fAttached = TRUE; |
200 | container.dwAttachedIndex = 0; | 204 | container.dwAttachedIndex = 0; |
201 | 205 | ||
diff --git a/src/burn/engine/container.h b/src/burn/engine/container.h index c2c1c9a8..d454a248 100644 --- a/src/burn/engine/container.h +++ b/src/burn/engine/container.h | |||
@@ -52,6 +52,12 @@ enum BURN_CAB_OPERATION | |||
52 | BURN_CAB_OPERATION_CLOSE, | 52 | BURN_CAB_OPERATION_CLOSE, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | enum BURN_CONTAINER_VERIFICATION | ||
56 | { | ||
57 | BURN_CONTAINER_VERIFICATION_NONE, | ||
58 | BURN_CONTAINER_VERIFICATION_HASH, | ||
59 | }; | ||
60 | |||
55 | 61 | ||
56 | // structs | 62 | // structs |
57 | 63 | ||
@@ -59,7 +65,6 @@ typedef struct _BURN_CONTAINER | |||
59 | { | 65 | { |
60 | LPWSTR sczId; | 66 | LPWSTR sczId; |
61 | BURN_CONTAINER_TYPE type; | 67 | BURN_CONTAINER_TYPE type; |
62 | BOOL fPrimary; | ||
63 | BOOL fAttached; | 68 | BOOL fAttached; |
64 | DWORD dwAttachedIndex; | 69 | DWORD dwAttachedIndex; |
65 | DWORD64 qwFileSize; | 70 | DWORD64 qwFileSize; |
@@ -69,6 +74,7 @@ typedef struct _BURN_CONTAINER | |||
69 | 74 | ||
70 | BYTE* pbHash; | 75 | BYTE* pbHash; |
71 | DWORD cbHash; | 76 | DWORD cbHash; |
77 | BURN_CONTAINER_VERIFICATION verification; | ||
72 | DWORD64 qwAttachedOffset; | 78 | DWORD64 qwAttachedOffset; |
73 | BOOL fActuallyAttached; // indicates whether an attached container is attached or missing. | 79 | BOOL fActuallyAttached; // indicates whether an attached container is attached or missing. |
74 | 80 | ||
diff --git a/src/burn/engine/payload.cpp b/src/burn/engine/payload.cpp index 72eb3476..392a3dd4 100644 --- a/src/burn/engine/payload.cpp +++ b/src/burn/engine/payload.cpp | |||
@@ -27,6 +27,8 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
27 | IXMLDOMNode* pixnNode = NULL; | 27 | IXMLDOMNode* pixnNode = NULL; |
28 | DWORD cNodes = 0; | 28 | DWORD cNodes = 0; |
29 | LPWSTR scz = NULL; | 29 | LPWSTR scz = NULL; |
30 | BOOL fChainPayload = pContainers && pLayoutPayloads; // These are required when parsing chain payloads. | ||
31 | BOOL fValidFileSize = FALSE; | ||
30 | 32 | ||
31 | // select payload nodes | 33 | // select payload nodes |
32 | hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes); | 34 | hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes); |
@@ -51,6 +53,7 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
51 | for (DWORD i = 0; i < cNodes; ++i) | 53 | for (DWORD i = 0; i < cNodes; ++i) |
52 | { | 54 | { |
53 | BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i]; | 55 | BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i]; |
56 | fValidFileSize = FALSE; | ||
54 | 57 | ||
55 | hr = XmlNextElement(pixnNodes, &pixnNode, NULL); | 58 | hr = XmlNextElement(pixnNodes, &pixnNode, NULL); |
56 | ExitOnFailure(hr, "Failed to get next node."); | 59 | ExitOnFailure(hr, "Failed to get next node."); |
@@ -63,27 +66,36 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
63 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath); | 66 | hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath); |
64 | ExitOnFailure(hr, "Failed to get @FilePath."); | 67 | ExitOnFailure(hr, "Failed to get @FilePath."); |
65 | 68 | ||
66 | // @Packaging | 69 | // @SourcePath |
67 | hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz); | 70 | hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath); |
68 | ExitOnFailure(hr, "Failed to get @Packaging."); | 71 | ExitOnFailure(hr, "Failed to get @SourcePath."); |
69 | 72 | ||
70 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1)) | 73 | if (!fChainPayload) |
71 | { | 74 | { |
75 | // All non-chain payloads are embedded in the UX container. | ||
72 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; | 76 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; |
73 | } | 77 | } |
74 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1)) | ||
75 | { | ||
76 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL; | ||
77 | } | ||
78 | else | 78 | else |
79 | { | 79 | { |
80 | hr = E_INVALIDARG; | 80 | // @Packaging |
81 | ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz); | 81 | hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz); |
82 | } | 82 | ExitOnFailure(hr, "Failed to get @Packaging."); |
83 | 83 | ||
84 | // @Container | 84 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1)) |
85 | if (pContainers) | 85 | { |
86 | { | 86 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; |
87 | } | ||
88 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1)) | ||
89 | { | ||
90 | pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL; | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | hr = E_INVALIDARG; | ||
95 | ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz); | ||
96 | } | ||
97 | |||
98 | // @Container | ||
87 | hr = XmlGetAttributeEx(pixnNode, L"Container", &scz); | 99 | hr = XmlGetAttributeEx(pixnNode, L"Container", &scz); |
88 | if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging) | 100 | if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging) |
89 | { | 101 | { |
@@ -93,52 +105,67 @@ extern "C" HRESULT PayloadsParseFromXml( | |||
93 | hr = ContainerFindById(pContainers, scz, &pPayload->pContainer); | 105 | hr = ContainerFindById(pContainers, scz, &pPayload->pContainer); |
94 | ExitOnFailure(hr, "Failed to to find container: %ls", scz); | 106 | ExitOnFailure(hr, "Failed to to find container: %ls", scz); |
95 | } | 107 | } |
96 | } | ||
97 | 108 | ||
98 | // @LayoutOnly | 109 | // @LayoutOnly |
99 | hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly); | 110 | hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly); |
100 | if (E_NOTFOUND != hr) | 111 | if (E_NOTFOUND != hr) |
101 | { | 112 | { |
102 | ExitOnFailure(hr, "Failed to get @LayoutOnly."); | 113 | ExitOnFailure(hr, "Failed to get @LayoutOnly."); |
103 | } | 114 | } |
104 | 115 | ||
105 | // @SourcePath | 116 | // @DownloadUrl |
106 | hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath); | 117 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl); |
107 | ExitOnFailure(hr, "Failed to get @SourcePath."); | 118 | if (E_NOTFOUND != hr) |
119 | { | ||
120 | ExitOnFailure(hr, "Failed to get @DownloadUrl."); | ||
121 | } | ||
108 | 122 | ||
109 | // @DownloadUrl | 123 | // @FileSize |
110 | hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl); | 124 | hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz); |
111 | if (E_NOTFOUND != hr) | 125 | if (E_NOTFOUND != hr) |
112 | { | 126 | { |
113 | ExitOnFailure(hr, "Failed to get @DownloadUrl."); | 127 | ExitOnFailure(hr, "Failed to get @FileSize."); |
114 | } | ||
115 | 128 | ||
116 | // @FileSize | 129 | hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize); |
117 | hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz); | 130 | ExitOnFailure(hr, "Failed to parse @FileSize."); |
118 | if (E_NOTFOUND != hr) | ||
119 | { | ||
120 | ExitOnFailure(hr, "Failed to get @FileSize."); | ||
121 | 131 | ||
122 | hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize); | 132 | fValidFileSize = TRUE; |
123 | ExitOnFailure(hr, "Failed to parse @FileSize."); | 133 | } |
124 | } | 134 | |
135 | // @Hash | ||
136 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz); | ||
137 | if (E_NOTFOUND != hr) | ||
138 | { | ||
139 | ExitOnFailure(hr, "Failed to get @Hash."); | ||
125 | 140 | ||
126 | // @Hash | 141 | hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash); |
127 | hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz); | 142 | ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash."); |
128 | ExitOnFailure(hr, "Failed to get @Hash."); | ||
129 | 143 | ||
130 | hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash); | 144 | if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification) |
131 | ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash."); | 145 | { |
146 | pPayload->verification = BURN_PAYLOAD_VERIFICATION_HASH; | ||
147 | } | ||
148 | } | ||
132 | 149 | ||
133 | if (pPayload->fLayoutOnly && pLayoutPayloads) | 150 | if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification) |
134 | { | 151 | { |
135 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pLayoutPayloads->rgItems), pLayoutPayloads->cItems + 1, sizeof(BURN_PAYLOAD_GROUP_ITEM), 5); | 152 | ExitOnRootFailure(hr = E_INVALIDDATA, "There was no verification information for payload: %ls", pPayload->sczKey); |
136 | ExitOnFailure(hr, "Failed to allocate memory for layout payloads."); | 153 | } |
154 | else if (BURN_PAYLOAD_VERIFICATION_HASH == pPayload->verification && !fValidFileSize) | ||
155 | { | ||
156 | ExitOnRootFailure(hr = E_INVALIDDATA, "File size is required when verifying by hash for payload: %ls", pPayload->sczKey); | ||
157 | } | ||
137 | 158 | ||
138 | pLayoutPayloads->rgItems[pLayoutPayloads->cItems].pPayload = pPayload; | 159 | if (pPayload->fLayoutOnly) |
139 | ++pLayoutPayloads->cItems; | 160 | { |
161 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pLayoutPayloads->rgItems), pLayoutPayloads->cItems + 1, sizeof(BURN_PAYLOAD_GROUP_ITEM), 5); | ||
162 | ExitOnFailure(hr, "Failed to allocate memory for layout payloads."); | ||
140 | 163 | ||
141 | pLayoutPayloads->qwTotalSize += pPayload->qwFileSize; | 164 | pLayoutPayloads->rgItems[pLayoutPayloads->cItems].pPayload = pPayload; |
165 | ++pLayoutPayloads->cItems; | ||
166 | |||
167 | pLayoutPayloads->qwTotalSize += pPayload->qwFileSize; | ||
168 | } | ||
142 | } | 169 | } |
143 | 170 | ||
144 | // prepare next iteration | 171 | // prepare next iteration |
diff --git a/src/burn/engine/payload.h b/src/burn/engine/payload.h index f28b437f..6fc6de5e 100644 --- a/src/burn/engine/payload.h +++ b/src/burn/engine/payload.h | |||
@@ -23,6 +23,13 @@ enum BURN_PAYLOAD_STATE | |||
23 | BURN_PAYLOAD_STATE_CACHED, | 23 | BURN_PAYLOAD_STATE_CACHED, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | enum BURN_PAYLOAD_VERIFICATION | ||
27 | { | ||
28 | BURN_PAYLOAD_VERIFICATION_NONE, | ||
29 | BURN_PAYLOAD_VERIFICATION_HASH, | ||
30 | BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE, | ||
31 | }; | ||
32 | |||
26 | 33 | ||
27 | // structs | 34 | // structs |
28 | 35 | ||
@@ -36,6 +43,7 @@ typedef struct _BURN_PAYLOAD | |||
36 | 43 | ||
37 | BYTE* pbHash; | 44 | BYTE* pbHash; |
38 | DWORD cbHash; | 45 | DWORD cbHash; |
46 | BURN_PAYLOAD_VERIFICATION verification; | ||
39 | 47 | ||
40 | LPWSTR sczSourcePath; | 48 | LPWSTR sczSourcePath; |
41 | BURN_CONTAINER* pContainer; | 49 | BURN_CONTAINER* pContainer; |
diff --git a/src/burn/engine/pseudobundle.cpp b/src/burn/engine/pseudobundle.cpp index 180cc621..1b2eae75 100644 --- a/src/burn/engine/pseudobundle.cpp +++ b/src/burn/engine/pseudobundle.cpp | |||
@@ -69,6 +69,11 @@ extern "C" HRESULT PseudoBundleInitialize( | |||
69 | memcpy_s(pPayload->pbHash, pPayload->cbHash, pbHash, cbHash); | 69 | memcpy_s(pPayload->pbHash, pPayload->cbHash, pbHash, cbHash); |
70 | } | 70 | } |
71 | 71 | ||
72 | if (BOOTSTRAPPER_RELATION_UPDATE == relationType) | ||
73 | { | ||
74 | pPayload->verification = BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE; | ||
75 | } | ||
76 | |||
72 | pPackage->Exe.fPseudoBundle = TRUE; | 77 | pPackage->Exe.fPseudoBundle = TRUE; |
73 | 78 | ||
74 | pPackage->type = BURN_PACKAGE_TYPE_EXE; | 79 | pPackage->type = BURN_PACKAGE_TYPE_EXE; |
diff --git a/src/burn/test/BurnUnitTest/CacheTest.cpp b/src/burn/test/BurnUnitTest/CacheTest.cpp index d0cc237f..e9ad555b 100644 --- a/src/burn/test/BurnUnitTest/CacheTest.cpp +++ b/src/burn/test/BurnUnitTest/CacheTest.cpp | |||
@@ -71,6 +71,8 @@ namespace Bootstrapper | |||
71 | payload.sczFilePath = L"CacheSignatureTest.File"; | 71 | payload.sczFilePath = L"CacheSignatureTest.File"; |
72 | payload.pbHash = pb; | 72 | payload.pbHash = pb; |
73 | payload.cbHash = cb; | 73 | payload.cbHash = cb; |
74 | payload.qwFileSize = 27; | ||
75 | payload.verification = BURN_PAYLOAD_VERIFICATION_HASH; | ||
74 | 76 | ||
75 | hr = CacheCompletePayload(package.fPerMachine, &payload, package.sczCacheId, sczPayloadPath, FALSE, CacheTestEventRoutine, CacheTestProgressRoutine, &context); | 77 | hr = CacheCompletePayload(package.fPerMachine, &payload, package.sczCacheId, sczPayloadPath, FALSE, CacheTestEventRoutine, CacheTestProgressRoutine, &context); |
76 | Assert::Equal(S_OK, hr); | 78 | Assert::Equal(S_OK, hr); |
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 001acaee..045c510e 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp | |||
@@ -71,7 +71,7 @@ namespace Bootstrapper | |||
71 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | 71 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); |
72 | 72 | ||
73 | Assert::Equal(107082ull, pPlan->qwEstimatedSize); | 73 | Assert::Equal(107082ull, pPlan->qwEstimatedSize); |
74 | Assert::Equal(506145ull, pPlan->qwCacheSizeTotal); | 74 | Assert::Equal(522548ull, pPlan->qwCacheSizeTotal); |
75 | 75 | ||
76 | fRollback = FALSE; | 76 | fRollback = FALSE; |
77 | dwIndex = 0; | 77 | dwIndex = 0; |