@joebigelow / wix-1 / commits / e84b6768

Don't follow junctions when recursing directories.

When deleting directories recursively, an elevated custom action following junctions in a user-writable location could recurse into any directory, including some that you might not want to be deleted. Therefore, avoid recursing into directories that are actually junctions (aka "reparse points"). This applies to: - The RemoveFoldersEx custom action (which doesn't actually do deletions but would instruct elevated MSI to delete on your behalf). - DTF's custom action runner.

Rob Mensching committed Mar 22, 2024 at 11:55 UTC e84b6768772c01e44dd55fb583cf78388ec7e48a
2 files changed +13 -3
src/dtf/SfxCA/SfxUtil.cpp
+3 -1
@@ -93,7 +93,9 @@ bool DeleteDirectory(const wchar_t* szDir)
93 StringCchCopy(szPath + cchDir + 1, cchPathBuf - (cchDir + 1), fd.cFileName);
94 if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
95 {
96 - if (wcscmp(fd.cFileName, L".") != 0 && wcscmp(fd.cFileName, L"..") != 0)
96 + if (wcscmp(fd.cFileName, L".") != 0
97 + && wcscmp(fd.cFileName, L"..") != 0
98 + && ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0))
99 {
100 DeleteDirectory(szPath);
101 }
src/ext/Util/ca/RemoveFoldersEx.cpp
+10 -2
@@ -38,6 +38,14 @@ static HRESULT RecursePath(
38 }
39 #endif
40
41 + // Do NOT follow junctions.
42 + DWORD dwAttributes = ::GetFileAttributesW(wzPath);
43 + if (dwAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
44 + {
45 + WcaLog(LOGMSG_STANDARD, "Path is a junction; skipping: %ls", wzPath);
46 + ExitFunction();
47 + }
48 +
49 // First recurse down to all the child directories.
50 hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath);
51 ExitOnFailure(hr, "Failed to allocate file search string in path: %S", wzPath);
@@ -210,10 +218,10 @@ extern "C" UINT WINAPI WixRemoveFoldersEx(
218
219 hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT);
220 ExitOnFailure(hr, "Failed to expand path: %S for row: %S", sczPath, sczId);
213 -
221 +
222 hr = PathBackslashTerminate(&sczExpandedPath);
223 ExitOnFailure(hr, "Failed to backslash-terminate path: %S", sczExpandedPath);
216 -
224 +
225 WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId);
226 hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, f64BitComponent, &dwCounter, &hTable, &hColumns);
227 ExitOnFailure(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId);