Repository navigation
Uninstall: reach the signed-in user's Filee, and never report success with Filee left behind - #1120
Merged
Merged
Conversation
… with Filee left behind The elevated uninstaller ran "Filee.exe --uninstall-cleanup" with its own rights. The pipe of a Filee without administrator rights refuses an elevated client (CurrentUserOnly compares the pipe's owner with the token's owner, which is Administrators when elevated), so that Filee never heard --quit: the command waited 20 s and exited 1 before cleaning up. Filee was then ended by force, and its startup entry, Explorer menu entries and engines stayed. With another account at the administrator prompt it cleaned that account's registry and could not even see the user's Filee. - The cleanup runs as the signed-in user, again once Filee has been ended if it did not finish; the startup entry goes anyway if it is in this account's registry, and the Uninstalled card says when the cleanup never finished. - The elevated uninstaller can see and end other accounts' programs. A Filee that still runs afterwards stops the uninstall before anything is deleted, instead of running on from the trash folder. - A file that can't be removed fails the uninstall and keeps the uninstall entry, uninstall.json and uninstall.exe, so it can run again. Before, the entry went regardless, and the card said Filee was gone. - A file renamed in place is deleted at the next restart together with its folder. Refs #1079 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review findings on the first commit, each checked against the code: - Only programs uninstall.json lists are ended or block the uninstall. With a folder the user chose, and the debug privilege, the uninstaller could end services and other accounts' programs, and report an unkillable one as Filee. - A second try after "files left" no longer warns that the cleanup failed: Filee.exe is gone because the first try ran it. The startup entry is still removed when it points here. - uninstall.json is never scheduled or renamed: after the restart we ask for, uninstalling again needs it. - A file renamed in place that Windows won't delete at the restart (it takes administrator rights) no longer fails the uninstall: nothing runs it and a second try wouldn't know its name. The entry goes and the card says where it stays. - "Still running" no longer comes from opening Filee.exe for writing: that also fails while Explorer or Apps in Settings has it mapped for its icon. It looks for a process named Filee whose path can't be read, machine-wide only. - The signed-in user is compared with Explorer's SID: a name can be the same in a domain and on this PC. - The debug privilege is on only while looking at or ending programs, so programs started later don't inherit it. - it.json: the new lines follow the file's indentation. Refs #1079 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A scan holding a file just as it is being removed failed the uninstall on the first try. Locked files now get about 2 seconds before they count as left: eight tries 250 ms apart, shared by the whole uninstall, so the wait stays the same however many files are locked. uninstall.json waits within the same budget, and is still never scheduled or renamed. With the trash on another volume File.Move is no longer tried: MOVEFILE_COPY_ALLOWED is documented to succeed with the original still in place when it can't delete it, which looked like a removed file, and each retry would copy it again. Refs #1079 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #1079. Not
Fixes: this covers the startup entry and the false success for certain, but we don't have the reporter's log, so why their Program Files folder survived is not confirmed.What was wrong
1. The cleanup never ran when Filee was in the tray (every machine-wide uninstall by an administrator). The uninstaller runs elevated and started
Filee.exe --uninstall-cleanupwith its own rights.SingleInstanceusesPipeOptions.CurrentUserOnly; the .NET 10 client (NamedPipeClientStream.ValidateRemotePipeUser) compares the pipe's owner withWindowsIdentity.Owner, and an elevated token's owner is Administrators, not the user. So the tray Filee's pipe refuses the elevated client,--quitnever arrives, the mutex wait runs out after 20 s andRunInstallerCommandreturns 1 beforeUninstallCleanup.Run(). The uninstaller only logged the exit code and killed Filee by force. The startup entry, the classic verb, Send To and the engines stayed.2. A standard user who gets an administrator's account at the prompt. The cleanup ran in the administrator's hive and exited 0, leaving the user's Run value.
ProgramsIncould not open the user's processes, so their Filee was neither listed nor ended (Killswallows the denial too). Its files were moved to the trash folder and it ran on from there, and could still offer updates.3. The uninstall entry was removed no matter what. A file that could not be deleted or moved was only passed to
DeleteAtRestart, whose failure was just logged, thenRegistry.DeleteKeyran and the card said "Filee is no longer on this computer".uninstall.jsonwas gone by then too, so no retry was possible. If security software refuses the deletes, this gives the reported state: not in Apps, Filee in Program Files, and it starts from the Run key. Those files only go at a real restart, not at a Fast Startup shutdown.4. A file renamed in place was deleted at restart, but its folder was never scheduled, so an empty folder stayed.
What changed
ISetupSystem.RunAsSignedInUser: the cleanup runs with Explorer's token (the existingStartAsShellUserpath, now also waiting for the exit code). If that fails it falls back to Setup's rights only when Setup runs as Explorer's account (compared by SID); otherwise it returns -1 rather than a false "clean".installer.uninstall.cleanup_failed). A missingFilee.exeis no failure (an earlier try took it), but the Run value is still removed.uninstall.jsonlists are ended or can block the uninstall: a folder chosen with/DIRmay hold other programs, and they are never touched.SeDebugPrivilegeonly while it looks at or ends programs, so it can reach other accounts' and programs started later don't inherit it. A Filee still running afterwards fails the uninstall before any file goes (installer.uninstall.still_running). So does, machine-wide only, a process named Filee whose path can't be read. It deliberately doesn't test whetherFilee.exeis in use: that is also true while Explorer or Apps in Settings has it mapped for its icon.installer.uninstall.files_left). The entry,uninstall.jsonanduninstall.exestay, and the first-phase uninstaller isn't released, so it can run again.uninstall.jsonitself is never scheduled or renamed, or the retry after a restart would say Filee isn't installed.uninstall.jsonwaits within the same budget.File.Moveisn't tried:MOVEFILE_COPY_ALLOWEDis documented to succeed with the original still in place when it can't delete it, which would have looked like a removed file (and been copied again on each retry). Not run: this machine has one volume.%TEMP%): the uninstall still succeeds, since nothing runs that file, and the card says where it stays (installer.uninstall.files_kept).Checked for and not found
Nothing restarts Filee during removal: no
RegisterApplicationRestart, watchdog or task.UpdateServiceonly starts Setup when the user asks. The window can't be closed during removal, and the entry was already the last thing removed if removal threw.Verification
dotnet format --verify-no-changes: clean.tests/Filee.Setup.Tests: 230 passed. Tests were also run with the fixes undone: 8UninstallerTestsfail on the oldUninstaller.cs(first commit), and 7 fail with the second commit's five changes undone together (therecord.Filesfilter, keepinguninstall.json, the missingFilee.exe, the renamed file, and the in-use check put back).System.IO.Pipes.dll10.0.1. That an elevated token's owner is Administrators is standard Windows behaviour, not something I could run here.LOAD_LIBRARY_AS_IMAGE_RESOURCErefuses a write-open with every share flag, and that the SID comparison with Explorer works without elevation.Not run: no real install or uninstall, and nothing elevated, so these have only been reasoned through:
RunAsShellUseritself,CreateProcessWithTokenWreturning a handle we can wait on, and the debug privilege across accounts. Please try once on a test machine before release: machine-wide install, Filee in the tray, uninstall from Settings.%TEMP%\Filee-Uninstall-*.logshould showFilee --uninstall-cleanup: exit code 0without a 20 s gap, and the Run value should be gone. Then the same with a standard user and another account at the prompt.Not changed
Installer.CloseFileehas the same problem as point 1: an elevated Setup'sFilee.exe --quitcan't reach the tray Filee, so it should wait 20 s and then force-kill it on updates, without Filee saving first. Left out to keep this PR on the uninstall; worth its own change.%APPDATA%.🤖 Generated with Claude Code