-
Notifications
You must be signed in to change notification settings - Fork 0
fix: harden git exec resolution in SourceLink metadata #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,10 +20,20 @@ | |||||||||||||||||||
| <PropertyGroup> | ||||||||||||||||||||
| <_StderrRedirect Condition="'$(OS)' == 'Windows_NT'"> 2>nul</_StderrRedirect> | ||||||||||||||||||||
| <_StderrRedirect Condition="'$(OS)' != 'Windows_NT'"> 2>/dev/null</_StderrRedirect> | ||||||||||||||||||||
|
|
||||||||||||||||||||
| <!-- Resolve git to a trusted absolute path so repo-local binary planting cannot hijack Exec. --> | ||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(GitExe)' != '' and $([System.IO.Path]::IsPathRooted('$(GitExe)'))">$(GitExe)</_GitExe> | ||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' != 'Windows_NT' and Exists('/usr/bin/git')">/usr/bin/git</_GitExe> | ||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' != 'Windows_NT' and Exists('/usr/local/bin/git')">/usr/local/bin/git</_GitExe> | ||||||||||||||||||||
|
Comment on lines
+25
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(ProgramW6432)\Git\cmd\git.exe')">$(ProgramW6432)\Git\cmd\git.exe</_GitExe> | ||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(ProgramFiles)\Git\cmd\git.exe')">$(ProgramFiles)\Git\cmd\git.exe</_GitExe> | ||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(ProgramFiles)\Git\bin\git.exe')">$(ProgramFiles)\Git\bin\git.exe</_GitExe> | ||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(LocalAppData)\Programs\Git\cmd\git.exe')">$(LocalAppData)\Programs\Git\cmd\git.exe</_GitExe> | ||||||||||||||||||||
|
Comment on lines
+28
to
+31
|
||||||||||||||||||||
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(ProgramW6432)\Git\cmd\git.exe')">$(ProgramW6432)\Git\cmd\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(ProgramFiles)\Git\cmd\git.exe')">$(ProgramFiles)\Git\cmd\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(ProgramFiles)\Git\bin\git.exe')">$(ProgramFiles)\Git\bin\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and Exists('$(LocalAppData)\Programs\Git\cmd\git.exe')">$(LocalAppData)\Programs\Git\cmd\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and '$(ProgramW6432)' != '' and Exists('$(ProgramW6432)\Git\cmd\git.exe')">$(ProgramW6432)\Git\cmd\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and '$(ProgramFiles(x86))' != '' and Exists('$(ProgramFiles(x86))\Git\cmd\git.exe')">$(ProgramFiles(x86))\Git\cmd\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and '$(ProgramFiles)' != '' and Exists('$(ProgramFiles)\Git\cmd\git.exe')">$(ProgramFiles)\Git\cmd\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and '$(ProgramFiles)' != '' and Exists('$(ProgramFiles)\Git\bin\git.exe')">$(ProgramFiles)\Git\bin\git.exe</_GitExe> | |
| <_GitExe Condition="'$(_GitExe)' == '' and '$(OS)' == 'Windows_NT' and '$(LocalAppData)' != '' and Exists('$(LocalAppData)\Programs\Git\cmd\git.exe')">$(LocalAppData)\Programs\Git\cmd\git.exe</_GitExe> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with the first Exec task and to improve robustness, it's advisable to add a condition here to ensure this task only runs if _GitExe has been successfully resolved. Without the condition, if _GitExe is empty, MSBuild will attempt to execute an empty command, which will fail. Although IgnoreExitCode="true" prevents a build failure, explicitly skipping the task is a cleaner approach.
<Exec Command=""$(_GitExe)" -C "$(_GitRoot)" config --get remote.origin.url$(_StderrRedirect)"
Condition="'$(_GitExe)' != ''"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to my other comments, adding a condition to this Exec task will make the logic more robust by preventing an attempt to run an empty command if a trusted git executable isn't found.
<Exec Command=""$(_GitExe)" -C "$(_GitRoot)" symbolic-ref --quiet HEAD$(_StderrRedirect)"
Condition="'$(_GitExe)' != ''"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To maintain consistency and prevent errors from attempting to run an empty command, please add a condition to this Exec task to ensure it only runs when _GitExe is defined.
<Exec Command=""$(_GitExe)" -C "$(_GitRoot)" rev-parse --abbrev-ref HEAD$(_StderrRedirect)"
Condition="'$(_GitExe)' != ''"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As with the other git commands in this target, this Exec task should also be conditional on _GitExe being set. This will prevent it from trying to execute an empty command if git is not found in one of the trusted locations.
<Exec Command=""$(_GitExe)" -C "$(_GitRoot)" rev-parse HEAD$(_StderrRedirect)"
Condition="'$(_GitExe)' != ''"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
In MSBuild property functions on the supported SDK/Visual Studio versions, doesSystem.IO.Path.IsPathRooted("C:git.exe")return true, and isSystem.IO.Path.IsPathFullyQualifiedavailable for enforcing a truly absolute path?💡 Result:
Yes. On Windows,
System.IO.Path.IsPathRooted("C:git.exe")returns true becauseIsPathRootedtreats “drive letter + colon” as “rooted” (even though it’s still drive-relative, not truly absolute). The .NET docs forIsPathFullyQualifiedshow the same behavior with"C:Documents": Rooted = True, Fully qualified = False. [1], [2]System.IO.Path.IsPathFullyQualified(...)exists on modern .NET / .NET Standard (not .NET Framework) (the API is documented as coming fromnetstandard.dll/System.Runtimeand is intended to distinguish"C:a"vs"C:\\a"). [1]MSBuild property functions can call public static .NET methods, but only those available in the runtime hosting MSBuild. [3]
Practical upshot for “supported SDK/VS versions”:
dotnet msbuild/dotnet build), you can usePath.IsPathFullyQualifiedto enforce a truly absolute path. [4]Path.IsPathFullyQualifiedis not available, so calling it in a property function will fail at evaluation time (you’ll need an alternate check, e.g., pattern-testing for^[A-Za-z]:[\\/]|^\\\\). [1], [3]Sources: [1] [2] [3] [4]
Require
$(GitExe)to be fully qualified and to exist before trusting it.Path.IsPathRootedaccepts drive-relative Windows paths likeC:git.exe(rooted, not fully qualified), which can resolve relative to the current directory and weakens this hardening. The check also short-circuits fallback probes even when the file doesn't exist, silently disabling git metadata on a stale override.Use
Path.IsPathFullyQualifiedon .NET SDK MSBuild (e.g.,dotnet build), or implement an equivalent check for .NET Framework MSBuild. Always pair withExistsvalidation.Suggested change
For .NET Framework MSBuild, replace
IsPathFullyQualifiedwith a pattern check or equivalent validation ensuring the path is truly absolute (e.g.,^[A-Za-z]:\\|^\\\\).🤖 Prompt for AI Agents