cargo-bins / cargo-quickinstall

pre-compiled binary packages for `cargo install`
Apache License 2.0
213 stars 9 forks source link

32-bit Windows treats `cargo-quickinstall.exe` as requiring UAC elevation #254

Open EliahKagan opened 4 weeks ago

EliahKagan commented 4 weeks ago

Since it looks like no i686 targets currently have quickinstall builds, this is a pretty minor issue, and I admit it may even be justified to close it as not worth fixing.

When a Windows executable has no manifest and is named with setup, update, or install in its name, even if not at a word boundary, Windows is more likely to guess that it requires UAC elevation to run. This seems to happen only for 32-bit Windows executables, and I encountered it for cargo-quickinstall on a 32-bit x86 Windows 10 system running the stable-i686-pc-windows-msvc Rust toolchain, after running cargo install cargo-quickinstall and attempting to run the executable:

PS C:\Users\ek> cargo install cargo-quickinstall
    Updating crates.io index
  Installing cargo-quickinstall v0.2.10
    Updating crates.io index
     Locking 30 packages to latest compatible versions
      Adding errno v0.2.8 (latest: v0.3.9)
      Adding linux-raw-sys v0.4.14 (latest: v0.6.4)
   Compiling windows_i686_msvc v0.52.5
   Compiling winapi v0.3.9
   Compiling log v0.4.22
   Compiling cfg-if v1.0.0
   Compiling fastrand v2.1.0
   Compiling tinyjson v2.5.1
   Compiling pico-args v0.5.0
   Compiling windows-targets v0.52.5
   Compiling windows-sys v0.52.0
   Compiling errno v0.2.8
   Compiling guess_host_triple v0.1.3
   Compiling tempfile v3.10.1
   Compiling home v0.5.9
   Compiling cargo-quickinstall v0.2.10
    Finished `release` profile [optimized] target(s) in 13.01s
  Installing C:\Users\ek\.cargo\bin\cargo-quickinstall.exe
   Installed package `cargo-quickinstall v0.2.10` (executable `cargo-quickinstall.exe`)
PS C:\Users\ek> cargo quickinstall --help
error: could not execute process `C:\Users\ek\.cargo\bin\cargo-quickinstall.exe quickinstall --help` (never executed)

Caused by:
  The requested operation requires elevation. (os error 740)

This resembles https://github.com/rust-lang/cargo/issues/393 and seems to happen only with the 32-bit Windows executable. This official summary of how, when an executable contains no manifest, the need for UAC elevation is guessed based on factors that include the executable's name, is somewhat ambiguous, but seems to indicate that this is only done on 32-bit Windows executables.

This does not happen with cargo-binstall or cargo-install-update, which have manifests (that specify asInvoker as the execution level). For example:

PS C:\Users\ek\.cargo\bin> mt.exe -nologo '-inputresource:cargo-install-update.exe;#1' -out:cargo-install-update.manifest ; cat cargo-install-update.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>
PS C:\Users\ek\.cargo\bin> mt.exe -nologo '-inputresource:cargo-binstall.exe;#1' -out:cargo-binstall.manifest ; cat cargo-binstall.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <assemblyIdentity type="win32" name="Binstall.Cli.binstall" version="1.7.3.0"></assemblyIdentity>

        <trustInfo>
                <security>
                        <!--
                        UAC settings:
                        - app should run at same integrity level as calling process
                        - app does not need to manipulate windows belonging to
                        higher-integrity-level processes
                        -->
                        <requestedPrivileges>
                                <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
                        </requestedPrivileges>
                </security>
        </trustInfo>

        <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
                <application>
                        <!-- Windows 10, 11 -->
                        <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"></supportedOS>
                        <!-- Windows 8.1 -->
                        <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"></supportedOS>
                        <!-- Windows 8 -->
                        <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>
                </application>
        </compatibility>

        <application xmlns="urn:schemas-microsoft-com:asm.v3">
                <windowsSettings xmlns:ws="http://schemas.microsoft.com/SMI/2020/WindowsSettings">
                        <ws:longPathAware xmlns:ws="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</ws:longPathAware>
                        <ws:activeCodePage xmlns:ws="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</ws:activeCodePage>
                        <ws:heapType xmlns:ws="http://schemas.microsoft.com/SMI/2020/WindowsSettings">SegmentHeap</ws:heapType>
                </windowsSettings>
        </application>
</assembly>

In contrast, the cargo-quickinstall executable has no manifest:

PS C:\Users\ek\.cargo\bin> mt.exe -nologo '-inputresource:cargo-quickinstall.exe;#1' -out:cargo-quickinstall.manifest

mt.exe : general error c101008c: Failed to read the manifest from the resource of file "cargo-quickinstall.exe". The specified image file did not contain a resource section.

(mt.exe is available in Developer Powershell for VS 2022. It can be run with -out:CON to directly dump manifests to the console, but this gives an error message at the end which seemed like it would confuse the output, so I didn't use that technique above. Manifests can also be viewed with sigcheck -m if sigcheck is installed.)

cargo-binstall has had a Windows executable manifest since https://github.com/cargo-bins/cargo-binstall/pull/224. cargo-install-update has had one since https://github.com/nabijaczleweli/cargo-update/commit/ef4346c96b1e55bb837557520e6ea09d3f0d867e, and its old readme provided some information on this kind of issue (though I did not succeed at getting an analogous workaround with a .exe.manifest file to work for cargo-quickinstall as had been recommended there for cargo-install-update). See also https://github.com/rust-lang/rfcs/issues/721.

If this is wanted, then I'd be interested to look into contributing it. However, given that there are currently no quickinstall builds that target 32-bit Windows, I understand there may currently be only minimal benefit to fixing this. On the other hand, if it is intended to build for i686 targets in the future, then this might be helpful.

NobodyXu commented 4 weeks ago

Thank for reporting!

Yes that is something we should add to our binary, to make sure it would run on 32-bit windows.