Closed Bug 236312 Opened 21 years ago Closed 21 years ago

Windows death after upgrade (PendingFileRenameOperations registry corruption)

Categories

(SeaMonkey :: Installer, defect)

x86
Windows 2000
defect
Not set
critical

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: martin.sheppard, Assigned: dveditz)

References

Details

(Keywords: dataloss, fixed1.7, verifyme)

Attachments

(4 files, 3 obsolete files)

User-Agent: Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113 Mozilla install stuffs up HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations Reproducible: Always Steps to Reproduce: 1. Install Windows Security Patch 2. Install Mozilla Actual Results: HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations was modified so that it deleted critical system files Expected Results: No Change to HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations I don't believe that this happened with the Mozilla 1.5 installer
That reg key is used by the MoveFileEx() API call to replace or delete in-use files. The Windows Security Patch you installed surely uses that call. I'm sure the Mozilla installer also uses it to replace any in-use files. No bug -> INVALID
Status: UNCONFIRMED → RESOLVED
Closed: 21 years ago
Resolution: --- → INVALID
Ok, I wasn't specific enough in my original description. Here are the exact details of reproducing the bug: - Start with Windows 2000 SP3 (or SP4), bare install - Install Mozilla 1.5 with Default Settings - Reboot (opotional) - Install Windows2000-KB824146-x86-ENU.exe (or any other Windows patch) without rebooting - Run QChain.exe (not necessary, but produces nice text file showing issue) - Install Mozilla 1.6 with Default Settings - Run QChain.exe (not necessary, but produces nice text file showing issue) - Reboot and watch Windows delete important system files The problem appears to be that when Mozilla 1.6 is installed it will first uninstall mozilla 1.5. The Mozilla 1.5 uninstaller adds a PendingFileRenameOperation to delete the uninstall executable. Next, the Mozilla 1.6 installer reads the PendingFileRenameOperations key, sees that it will delete its own uninstaller after the reboot and removes the delete operation from the key. The trouble is that if there are other operations in the key then it mangles them for some reason with the effect that on the next reboot, system files are deleted rather than being replaced with a newer version. See the attachment which shows how the registry key changes through the install process. The best way to implement this would probably be to create a temporary file for the new uninstaller and use MoveFileEx, so that on the next reboot the old Mozilla 1.5 uninstaller will be delted and then the new uninstaller will be renamed to replace it. This is a serious bug - depending on which Windows updates you installed it can render your computer unbootable and it has done this to a number of our computers.
Status: RESOLVED → UNCONFIRMED
Resolution: INVALID → ---
Ok. That description is much better. It appears that there is something wrong with the ClearWinRegUninstallFileDeletion function : http://lxr.mozilla.org/seamonkey/source/xpinstall/wizard/windows/setup/extra.c#516 The installer does use MoveFileEX() to replace in-use files, but judging by the comments above the ClearWinRegUninstallFileDeletion() function, the installer is manually editing the contents of the PendingFileRenameOperations key. (And corrupting it?)
Assignee: general → general
Component: Browser-General → Installer
QA Contact: general → bugzilla
Confirming. Easier steps to reproduce: (Without doing windows updates and risking damage to your system) 1. Install MoveOnBoot http://www.webattack.com/get/moveonboot.html 2. Create two text files. Eg. "testnew.txt" and "testold.txt" 3. Right-click one of the files and use MoveOnBoot to move one file to the other. (To simulate replacing an in-use file) 4. Look at the following Registry Value: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations 5. Run Mozilla installer for newer version than is currently installed. (eg. 1.5 -> 1.6, or 1.6 -> Nightly) 6. Look at the following Registry Value: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations Expected Results: The values should be *identical* Actual Results: The registry value is different after the mozilla installer processes it. After processing there are two problems: 1) There is an extra NULL character at the end. (Perhaps not critical) 2) The '\' character that separates the designated source file and the destination file is replaced with a NULL. (essentially changing every single "replace" operation with two "delete" operations)
Status: UNCONFIRMED → NEW
Ever confirmed: true
Keywords: dataloss
The problem is that the PendingFileRenameOperations registry value can have items contained in it of two types: 1) szDestFile\0\0 (for file deletes) 2) szSrcFile\0szDstFile\0\0 (for file replacement) The ClearWinRegUninstallFileDeletion() function is treating the above items as strings, and due to the embedded null in the second case is treating it as two separate items when it should be one. When it reads in and re-writes the registry value, it is being corrupted.
This patch puts a single null between arguments of a single move command, and double nulls between items of the PendingFileRenameOperations registry value.
Attachment #143085 - Flags: superreview?(dveditz+bmo)
Attachment #143085 - Flags: review?(bsmedberg)
The patch looks a little complicated to me - it feels to me like there there must be a slightly simpler algorithm, but I'm not sure what it might be since I haven't looked at all the code in that function, only the patch. A possible alternative which doesn't involve messing with the PendingFileRenameOperations registry key at all is the following algorithm: 1. Copy uninstaller to C:\winnt\uninstallername.exe and to c:\winnt\sometempfile 2. Execute MoveFileEX(c:\winnt\sometempfile, C:\winnt\uninstallername.exe, DELAY till next reboot) On the next reboot the uninstaller will be removed and then replaced. Also, an uninstall will still work correctly even if executed before the reboot happens. I don't care which implementation is used, but I thought I'd suggest it as an alternative. Martin.
Comment on attachment 143085 [details] [diff] [review] Patch to enable proper parsing of PendingFileRenameOperations WD: you're adding tabs in a few places. Tabs are evil. See http://www.mozilla.org/hacking/mozilla-style-guide.html#Visual Also, you're patch has DOS linefeeds, so it won't apply (at least on Unix). I don't know the best way to remove them. If you generate a cvs diff, I think they won't be there.
Attachment #143085 - Attachment is obsolete: true
Attachment #143085 - Flags: superreview?(dveditz+bmo)
Attachment #143085 - Flags: review?(bsmedberg)
Attachment #143535 - Flags: review?(bsmedberg)
I will not be able to review this for a week at least.
Attachment #143535 - Flags: superreview?(dveditz+bmo)
Attachment #143535 - Flags: review?(dveditz+bmo)
Attachment #143535 - Flags: review?(bsmedberg)
This probably should block 1.7 Firefox has its own copy of the installer, it'll have this bug plus any others we've fixed since the fork (bad Ben, no biscuit). the OS/2 installer also appears to have its own copy, but that makes quite a bit more sense given the OS-specific calls in an install. I can't find an analog of this section in there, but cc'ing mkaply just to make sure. Sean, any thoughts?
Assignee: general → dveditz+bmo
Flags: blocking1.7?
definitely a blocker but not an OS/2 issue - we don't have the same sort of cleanup stuff as Windows.
Flags: blocking1.7? → blocking1.7+
This is a very serious bug. It can render your system unusable. It's easy to run into this especially when you download and install windows updates automatically, there are times when you don't want to reboot. Personally I've run into this and I got a blue screen (I couldn't login) because of missing user32.dll, I had to reinstall windows ! IMHO the patch here should be reviewed ASAP and at this point no Mozilla release should happen until this bug is fixed.
Comment on attachment 143535 [details] [diff] [review] Cleaned up version of patch (no ^M or tabs) >+ BOOL bPendingFileRename = FALSE; >+ int szInMultiStrIndex = 0; > > if(!GetWindowsDirectory(szWinDir, sizeof(szWinDir))) > return; > > wsprintf(szLCUninstallFilenameLongBuf, "%s\\%s", szWinDir, sgProduct.szUninstallFilename); > GetShortPathName(szLCUninstallFilenameLongBuf, szLCUninstallFilenameShortBuf, sizeof(szLCUninstallFilenameShortBuf)); >@@ -559,26 +561,56 @@ void ClearWinRegUninstallFileDeletion(vo > if(!strstr(szLCKeyBuf, szLCUninstallFilenameLongBuf) && !strstr(szLCKeyBuf, szLCUninstallFilenameShortBuf)) > { a local for lstrlen(szPtrIn) seems reasonable: > if((dwOutMultiStrLen + lstrlen(szPtrIn) + 3) <= sizeof(szOutMultiStr)) //first use > { > /* uninstaller not found, so copy the szPtrIn string to szPtrOut buffer */ > lstrcpy(szPtrOut, szPtrIn); >+ >+ /* the following section is conditional because there are two possible entries in PendingFileRenameOperations >+ * szDstfile\0\0 is for deletions, szSrcFile\0szDstFile\0\0 is for file replacement (move) >+ * since the string operations will stop at the null in the middle of the move command, it is done in 2 passes >+ * only inserting one null between move arguments, and two nulls between the MoveFileEx operations >+ */ >+ szInMultiStrIndex += lstrlen(szPtrIn); //second use these two codepaths are very similar: >+ if ( (szInMultiStr[szInMultiStrIndex] == '\0') && (szInMultiStr[szInMultiStrIndex + 1] != '\0' )) >+ { >+ szInMultiStrIndex += 1; /* there is only 1 NULL byte between parameters in a */ >+ dwOutMultiStrLen += lstrlen(szPtrIn) + 1; /* move command */ //third use >+ szPtrOut = &szPtrOut[lstrlen(szPtrIn) + 1]; /* */ //fourth use >+ bPendingFileRename = TRUE; /* working with a move operation, rather than delete */ >+ } >+ else >+ { >+ szInMultiStrIndex += 2; >+ dwOutMultiStrLen += lstrlen(szPtrIn) + 2; /* there are actually 2 NULL bytes between the strings */ //alt third use >+ szPtrOut = &szPtrOut[lstrlen(szPtrIn) + 2]; /* there are actually 2 NULL bytes between the strings */ //alt fourth use >+ bPendingFileRename = FALSE; /* working with a delete operation, rather than move */ >+ } > } > else > { > bFoundUninstaller = FALSE; > /* not enough memory; break out of while loop. */ > break; > } > } > else >+ { >+ szInMultiStrIndex += lstrlen(szPtrIn) + 2; /* increment to next string in the REG_MULTI_SZ */ >+ bPendingFileRename = FALSE; /* you are not in the middle of a 2-pass move command */ > bFoundUninstaller = TRUE; >+ } >+ >+ if(bPendingFileRename) >+ { >+ szPtrIn = &szPtrIn[lstrlen(szPtrIn) + 1]; /* there is only 1 NULL byte between strings in a move */ //i'm not sure what use number this is, perhaps fifth >+ } >+ else >+ { >+ szPtrIn = &szPtrIn[lstrlen(szPtrIn) + 2]; /* there are actually 2 NULL bytes between the strings */ //i'm not sure what use number this is, perhaps alt fifth >+ } > }while(*szPtrIn != '\0'); > } you /could/ do this, but i'm not sure it's actually better... bPendingFileMove = (szInMultiStr[szInMultiStrIndex] != '\0') || (szInMultiStr[szInMultiStrIndex + 1] == '\0'); szInMultiStrIndex += 1 + bPendingFileMove; dwOutMultiStrLen += lstrlen(szPtrIn) + 1 + bPendingFileMove; szPtrOut = &szPtrOut[lstrlen(szPtrIn) + 1 + bPendingFileMove];
Comment on attachment 143535 [details] [diff] [review] Cleaned up version of patch (no ^M or tabs) Changing SR based on offlist discussion with roc. However, he will not SR until a R has been done.
Attachment #143535 - Flags: superreview?(dveditz+bmo) → superreview?(roc)
I am looking into the r=
Comment on attachment 143535 [details] [diff] [review] Cleaned up version of patch (no ^M or tabs) taking this off my superreview queue until a reviewer is found.
Attachment #143535 - Flags: superreview?(roc)
Attached patch Alternate fix (obsolete) — Splinter Review
Attachment #148094 - Flags: superreview?(roc)
Attachment #148094 - Flags: review?(ssu0262)
Comment on attachment 148094 [details] [diff] [review] Alternate fix r=ssu via mail
Attachment #148094 - Flags: review?(ssu0262) → review+
Summary: Mozilla 1.6 install stuffs up PendingFileRenameOperations registry key → Windows death after upgrade (PendingFileRenameOperations registry corruption)
Attachment #148094 - Flags: superreview?(roc)
Attachment #148094 - Flags: superreview?(dougt)
Attachment #148094 - Flags: approval1.7?
Comment on attachment 148094 [details] [diff] [review] Alternate fix Why do you have to allocate here: pathToMatch = strdup(aPathToMatch); More comments in the WHILE loop would be nice. Why do you need to flush (RegFlushKey(hkResult);) at this point? Can't you wait until windows is ready to do that? You can reuse oldMaxValueLen and get rid of newMaxValueLen. I haven't convinced myself that your memmove is correct. It would be nice to know what data was stored in the regkey. I guess I am lost on the variable names: np, op. I thought that op is short for operation. If that is the case, I think this might be wrong: if (StrStrI(op, pathToMatch)) Isn't the path in np? Oh well, just need to be clear on what you are parsing.
> Why do you have to allocate here: > pathToMatch = strdup(aPathToMatch); You are correct, it is not needed anymore. I believe that it was left over from when it did a string conversion to lowercase for parsing reasons, where we didn't want to alter the original string. StrStrI() solves the problem.
Attached patch address review comments (obsolete) — Splinter Review
Got rid of leftover pathToMatch strdup, better variable names, only write back to the registry if we've actually changed the string.
Attachment #148094 - Attachment is obsolete: true
Comment on attachment 148178 [details] [diff] [review] address review comments Carrying over r=ssu
Attachment #148178 - Flags: superreview?(dougt)
Attachment #148178 - Flags: review+
Attachment #148178 - Flags: approval1.7?
Attachment #148094 - Flags: superreview?(dougt)
Attachment #148094 - Flags: approval1.7?
Attachment #148178 - Attachment is obsolete: true
Attachment #148178 - Flags: superreview?(dougt)
Attachment #148178 - Flags: approval1.7?
Attachment #148180 - Flags: superreview?(dougt)
Attachment #148180 - Flags: review+
Attachment #148180 - Flags: approval1.7?
Comment on attachment 148180 [details] [diff] [review] same, with added comments per sr feedback a=chofmann for 1.7
Attachment #148180 - Flags: approval1.7? → approval1.7+
Attachment #143535 - Flags: review?(dveditz)
Attachment #148180 - Flags: superreview?(dougt) → superreview+
Fix checked in to trunk and 1.7 branch
Status: NEW → RESOLVED
Closed: 21 years ago21 years ago
Keywords: fixed1.7
Resolution: --- → FIXED
Blocks: 243373
Keywords: verifyme
Product: Browser → Seamonkey
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: