git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 1/1] mingw: embed a manifest to trick UAC into Doing The Right Thing

From
Cesar Eduardo Barros via GitGitGadget <gitgitgadget@gmail.com>
Date
Jun 27, 2019, 08:49 UTC
Message-ID
<781bc458f2f72b435b9ae1f7b684ef60fe03c810.1561625372.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.214.git.gitgitgadget@gmail.com>
From: Cesar Eduardo Barros <cesarb@cesarb.net>

On Windows >= Vista, not having an application manifest with a requestedExecutionLevel can cause several kinds of confusing behavior.

The first and more obvious behavior is "Installer Detection" of the "User Account Control" (also known as "UAC") feature, where Windows sometimes decides (by looking at things like the file name and even sequences of bytes within the executable) that an executable is an installer and should run elevated (causing the well-known popup dialog to appear). In Git's context, subcommands such as "git patch-id" or "git update-index" fall prey to this behavior.

The second and more confusing behavior is "File Virtualization". It means that when files are written without having write permission, it does not fail (as expected), but they are instead redirected to somewhere else. When the files are read, the original contents are returned, though, not the ones that were just written somewhere else. Even more confusing, not all write accesses are redirected; Trying to write to write-protected .exe files, for example, will fail instead of redirecting.

In addition to being unwanted behavior, File Virtualization causes dramatic slowdowns in Git (see for instance http://code.google.com/p/msysgit/issues/detail?id=320).

A third unwanted behavior of Windows >= Vista is that it lies about the Windows version when calling `GetWindowsVersionEx()`.

There are two ways to prevent these unwanted behaviors: Either you embed an application manifest (which really is an XML document conforming to a specific schema) within all your executables, or you add an external manifest (a file with the same name followed by `.manifest`) to all your executables. Since Git's builtins are hardlinked (or copied), it is simpler and more robust to embed a manifest.

Recent enough MSVC compilers already embed a working internal manifest, and building with mingw-w64 (which is the case in Git for Windows' SDK) does it, too, but for MinGW you have to do so by hand.

In any case, it is better to be explicit about this manifest, that way changes in the compiler toolchain won't surprise us (as mingw-w64 once did when it broke `GetWindowsVersionEx()` by mistake).

References:
  - New UAC Technologies for Windows Vista
    http://msdn.microsoft.com/en-us/library/bb756960.aspx
  - Create and Embed an Application Manifest (UAC)
    http://msdn.microsoft.com/en-us/library/bb756929.aspx
Signed-off-by: Cesar Eduardo Barros <cesarb@cesarb.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/win32/git.manifest | 25 +++++++++++++++++++++++++
 git.rc                    |  2 ++
 2 files changed, 27 insertions(+)
 create mode 100644 compat/win32/git.manifest
diff --git a/compat/win32/git.manifest b/compat/win32/git.manifest
new file mode 100644
index 0000000000..771e3cce43
--- /dev/null
+++ b/compat/win32/git.manifest
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+	<assemblyIdentity type="win32" name="Git" version="0.0.0.1" />
+	<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+		<security>
+			<requestedPrivileges>
+				<requestedExecutionLevel level="asInvoker" uiAccess="false" />
+			</requestedPrivileges>
+		</security>
+	</trustInfo>
+	<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+		<application>
+			<!-- Windows Vista -->
+			<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+			<!-- Windows 7 -->
+			<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+			<!-- Windows 8 -->
+			<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+			<!-- Windows 8.1 -->
+			<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+			<!-- Windows 10 -->
+			<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+		</application>
+	</compatibility>
+</assembly>
diff --git a/git.rc b/git.rc
index 49002e0d54..cc3fdc6cc6 100644
--- a/git.rc
+++ b/git.rc
@@ -20,3 +20,5 @@ BEGIN
     VALUE "Translation", 0x409, 1200
   END
 END
+
+1 RT_MANIFEST "compat/win32/git.manifest"
-- 
gitgitgadget
Previous: Johannes Schindelin via GitGitGadget
Message 2 of 2 in “windows: embed a manifest”
  1. 0/1 windows: embed a manifestJohannes Schindelin via GitGitGadget, Jun 27, 2019
  2. 1/1 mingw: embed a manifest to trick UAC into Doing The Right ThingCesar Eduardo Barros via GitGitGadget, Jun 27, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.