Skip to content
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

Update Rust crate gix-path to v0.10.11 [SECURITY] #12

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

renovate[bot]
Copy link

@renovate renovate bot commented Sep 19, 2024

This PR contains the following updates:

Package Type Update Change
gix-path dependencies patch 0.10.9 -> 0.10.11

GitHub Vulnerability Alerts

CVE-2024-45305

Summary

gix-path executes git to find the path of a configuration file that belongs to the git installation itself, but mistakenly treats the local repository's configuration as system-wide if no higher scoped configuration is found. In rare cases, this causes a less trusted repository to be treated as more trusted, or leaks sensitive information from one repository to another, such as sending credentials to another repository's remote.

Details

In gix_path::env, the underlying implementation of the installation_config and installation_config_prefix functions calls git config -l --show-origin and parses the first line of the output to extract the path to the configuration file holding the configuration variable of highest scope:

https:/Byron/gitoxide/blob/12251eb052df30105538fa831e641eea557f13d8/gix-path/src/env/git/mod.rs#L91

https:/Byron/gitoxide/blob/12251eb052df30105538fa831e641eea557f13d8/gix-path/src/env/git/mod.rs#L112

While the configuration variable of highest scope is not usually in the local scope, there are practical situations where this occurs:

  • A configuration file truly associated with the installation is not present on all systems and can occasionally be empty. Likewise, there may be no variables in the global scope.
  • Configuration files associated with those higher scopes may be deliberately skipped by setting the GIT_CONFIG_SYSTEM and GIT_CONFIG_GLOBAL environment variables to /dev/null (or to NUL on Windows). This prevents gix-path from finding the path of configuration files for those scopes, while not preventing downstream components such as the function in gix-config from reporting a local path as being associated with the installation.
  • The GIT_CONFIG_NOSYSTEM environment variable can be used to disable configuration associated with the installation. (GIT_CONFIG_NOSYSTEM=1 is more powerful than GIT_CONFIG_SYSTEM=/dev/null on systems where an additional "unknown" scope is associated with the installation, as occurs on macOS with Apple Git.) This will cause the local scope to be the highest nonempty scope under even more situations, though in practice it is less dangerous because most, though possibly not all, downstream components would disregard the value.

A user may use either or both of the latter two techniques to turn off an undesired configuration or to create a more replicable environment. Such a user would expect that this results in a more controlled configuration.

Often, when located inside one repository, a user performs operations on that repository or that are not specific to any repository. In such use, local configuration is typically desired or at least acceptable, and mistaking it as coming from another scope is not typically harmful.

However, sometimes a user is in one repository and operates on another repository. A major case where this occurs is cloning one repository while located in another. This can be done in an ad-hoc fashion, including when cloning the repository outside of the one we are inside. It may also potentially be automated by an application for purposes such as submodule handling. Two kinds of problems are anticipated:

  • A less secure configuration may be set for a specific repository where it is judged acceptable, even though it would not be wanted for other repositories, such as to enable a protocol or set up debugging.
  • More likely, a configuration that supplies secrets for use in one repository's remote can be used to send those secrets to another repository's remote.

PoC

In this example, we send mock Authorization: Basic ... credentials meant for one repository's remote to another remote, by running gix while inside the first repository to clone the second repository.

These instructions are written for a Unix shell, but they will work in other shells, including in PowerShell on Windows if the method of setting environment variables is adapted and /dev/null is replaced with NUL. This procedure is likely to demonstrate the problem on all systems except macOS. This is due to the high-scoped "unknown" configuration that usually accompanies Apple Git, and reflects that gix-path is in practice much less vulnerable on macOS (though still potentially vulnerable).

  1. Install dummyhttp to serve as a local HTTP server for the demonstration.

  2. Obtain a build of gitoxide with the max feature set enabled. While this vulnerability affects other builds, this example requires max for http.extraHeader support.

    Running cargo install gitoxide will install such a build though it may build against a patched version of gix-path. Cloning the repository (12251eb052df30105538fa831e641eea557f13d8 and earlier are affected) and building with cargo build or cargo install --path . are also sufficient. In contrast, installing from published binaries with binstall or quickinstall does not provide the max feature, as of this writing.

  3. Run: dummyhttp -i 127.0.0.1 -c 403 -v

  4. In a separate terminal, create a new local repository and set up a mock remote and http.extraHeader configuration:

    git init myrepo
    cd myrepo
    git remote add origin http://127.0.0.1:8080/mygit.git
    git config --local http.extraHeader 'Authorization: Basic abcde'
  5. Make sure the testing setup is working by running gix fetch in the repository and checking that it fails in the expected way. In the terminal where that is run, a message should be shown indicating an HTTP 403 error. The more interesting output is in the terminal where dummyhttp is running, which should look like this:

    2024-30-30 03:30:16 127.0.0.1:55689 GET /myrepo.git/info/refs?service=git-upload-pack HTTP/1.1
    ┌─Incoming request
    │ GET /myrepo.git/info/refs?service=git-upload-pack HTTP/1.1
    │ Accept: */*
    │ Authorization: Basic abcde
    │ Git-Protocol: version=2
    │ Host: 127.0.0.1:8080
    │ User-Agent: git/oxide-0.42.2
    ┌─Outgoing response
    │ HTTP/1.1 403 Forbidden
    │ Content-Length: 9
    │ Content-Type: text/plain; charset=utf-8
    │ Date: Fri, 30 Aug 2024 03:30:16 -0400
    

    Some details may differ, especially dates and times. But Authorization: Basic abcde should be shown.

  6. Now, in the terminal where you ran gix fetch, try cloning a separate repository:

    gix clone http://127.0.0.1:8080/other.git

    Check the output appended in the terminal where dummyhttp is running. This is to observe that Authorization: Basic abcde was rightly not sent.

    Alternatively, if it does appear, then your system may be in one of the uncommon configurations that is vulnerable without further action.

  7. Now rerun that command, but with a modified environment, to cause gix-path to wrongly treat configuration from the local scope as being associated with the git installation:

    env GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_GLOBAL=/dev/null gix clone http://127.0.0.1:8080/other.git

    Check the output appended in the terminal where dummyhttp is running. Observe that Authorization: Basic abcde was wrongly sent.

While this procedure uses the same remote host for both repositories, this is not a required element. If the second repository had a different, untrusted host, the extra header would still be sent.

Impact

It is believed to be very difficult to exploit this vulnerability deliberately, due to the need either to anticipate a situation in which higher-scoped configuration variables would be absent, or to arrange for this to happen. Although any operating system may be affected, users running Apple Git on macOS are much less likely to be affected.

In the example shown above, more secure general practices would avoid it: using a credential manager, or even using http.<url>.extraHeader with as specific a <url> as possible, rather than the more general http.extraHeader. Many scenarios are analogous: if each repository's configuration is as secure as possible for how the repository is used, and secrets are stored securely and separately, then the circumstances under which an unacceptably unsecure configuration is used, or under which a leak of credentials would occur, become unlikely.

CVE-2024-45405

Summary

gix-path runs git to find the path of a configuration file associated with the git installation, but improperly resolves paths containing unusual or non-ASCII characters, in rare cases enabling a local attacker to inject configuration leading to code execution.

Details

In gix_path::env, the underlying implementation of the installation_config and installation_config_prefix functions calls git config -l --show-origin to find the path of a file to treat as belonging to the git installation.

Affected versions of gix-path do not pass -z/--null to cause git to report literal paths (650a1b5). Instead, to cover the occasional case that git outputs a quoted path, they attempt to parse the path by stripping the quotation marks:

https:/Byron/gitoxide/blob/1cfe577d461293879e91538dbc4bbfe01722e1e8/gix-path/src/env/git/mod.rs#L138-L142

The problem is that, when a path is quoted, it may change in substantial ways beyond the concatenation of quotation marks. If not reversed, these changes can result in another valid path that is not equivalent to the original.

This is not limited to paths with unusual characters such as quotation marks or newlines. Unless git is explicitly configured with core.quotePath set to false, it also happens when the path contains most non-ASCII characters, including accented or non-English letters. For example, é is transformed to \303\251, with literal backslashes. (This is an octal representation of the bytes in its UTF-8 encoding. This behavior is not limited to systems that encode paths with UTF-8 on disk.)

Rarely, the configuration file gix-path wrongly attempts to open can be created by an attacker who has a limited user account on the system. The attacker would often need to request an account username tailored to carrying out the attack.

PoC

Quick demonstration on Unix

On a Unix-like system in which Git supports no higher scope than system for configuration variables (i.e., not on macOS with Apple Git), in a locale that supports UTF-8, with gitoxide installed, run:

mkdir myrepo
cd myrepo
git init
printf '[real]\n\trealvar = realval\n' > 'é'
printf '[fake]\n\tfakevar = fakeval\n' > '\303\251'
GIT_CONFIG_SYSTEM='é' gix config

If the above conditions are satisfied and the gix command was built against an affected version of gix-path, then the last command's output looks something like this:


# From '\303\251' (GitInstallation)
[fake]
        fakevar = fakeval

# From 'é' (System)
[real]
        realvar = realval

# From '/home/ubuntu/.gitconfig' (User)
[init]
        defaultBranch = main

# From './.git/config' (Local)
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true

Demonstration across user accounts on Windows

On a test system running Windows on which Git for Windows is not installed system-wide—resembling a scenario in which users who wish to use Git are expected to install it themselves for their accounts—create two accounts, with these usernames:

  • Renée, the target of the attack. This user may be a limited user or an administrator. Its user profile directory is assumed to be C:\Users\Renée.
  • Ren, the user who carries out the attack. This user should be a limited user, since an administrator would not need to exploit this vulnerability to inject configuration. Its user profile directory is assumed to be C:\Users\Ren.

As Ren, run these commands in PowerShell:

$d = "$HOME\303\251e\AppData\Local\Programs\Git\etc"
mkdir $d
git config --file $d\gitconfig core.sshCommand calc.exe
icacls $HOME\303 /grant 'Renée:(RX)' /T

(The gitconfig file can instead be written manually, in which case Ren need not have git.)

As Renée:

  1. Install Git for Windows in the default location for non-systemwide installations, which for that user account is inside C:\Users\Renée\AppData\Local\Programs. For a non-administrative installation, Git for Windows will pick this location automatically. Allow the installer to place the directory containing git in the user's PATH, as it does by default.

    (The scenario can be modified for any location the attacker can predict. So, for example, Renée can install Git for Windows with scoop, and Ren could carry out the attack with correspondingly modified path components in place of AppData\Local\Programs\Git.)

  2. Install gitoxide using any common technique, such as by installing Rust and then running cargo install gitoxide.

  3. Open a PowerShell window and run a gix command that attempts to run the SSH client for transport. For example:

    gix clone ssh://localhost/myrepo.git

    At least one, and usually two, instances of the Windows calculator will pop up. This happens because calc.exe was configured in the fake configuration file the user Ren was able to cause to be used, by placing it at the location gix-path wrongly resolved the path of Renée's own configuration file to.

The gitconfig file written by the attacker can be adjusted with an arbitrary choice of payload, or to set other configuration variables.

Impact

On a single-user system, it is not possible to exploit this, unless GIT_CONFIG_SYSTEM and GIT_CONFIG_GLOBAL have been set to unusual values or Git has been installed in an unusual way. Such a scenario is not expected.

Exploitation is unlikely even on a multi-user system, though it is plausible in some uncommon configurations or use cases. It is especially unlikely with Apple Git on macOS, due to its very high scoped configuration in /Library or /Applications that would be detected instead, as in CVE-2024-45305.

The likelihood of exploitation may be higher on Windows, where attacks such as those shown in the Windows proof-of-concept above can be performed due to the status of \ as a directory separator, and where there is no restriction on usernames containing accented or non-English letters (though the latter is also permitted on some other systems). Even then, complex user interaction is required. In most cases, a system administrator would have to approve an innocuous-seeming username, and then the targeted user (who could be the same or a different user) would have to use an application that uses gix-path.

In general, exploitation is more likely to succeed if at least one of the following applies:

  • Users are expected to install git themselves, and are likely to do so in predictable locations.
  • Locations where git is installed, whether due to usernames in their paths or otherwise, contain characters that git quotes by default in paths, such as non-English letters and accented letters.
  • A custom system-scope configuration file is specified with the GIT_CONFIG_SYSTEM environment variable, and its path is in an unusual location or has strangely named components.
  • A system-scope configuration file is absent, empty, or suppressed by means other than GIT_CONFIG_NOSYSTEM. Currently, gix-path can treat a global-scope configuration file as belonging to the installation if no higher scope configuration file is available. This increases the likelihood of exploitation even on a system where git is installed system-wide in an ordinary way.

However, exploitation is expected to be very difficult even under any combination of those factors.

Although the effect here is similar to CVE-2022-24765 once exploited, a greater degree of user interaction would usually be required, and the attack complexity here is much higher because the necessary conditions are uncommon and challenging to predict.


Release Notes

Byron/gitoxide (gix-path)

v0.10.11: gix-path v0.10.11

Compare Source

Bug Fixes
  • Don't require usable temp dir to get installation config
    When running git config -l ... to find the configuration file
    path associated with the git installation itself, the current
    working directory for the subprocess was set to the current
    directory prior to #​1523, and to /tmp or a /tmp-like directory
    since #​1523 (which improved performance and security).

    This builds on #​1523, as well as on subsequent changes to run git
    in a way that its behavior depends less on its CWD, by making an
    even more robust choice of CWD for the subprocess, so that the CWD
    is less likely to be deeply nested or on network storage; more
    likely to exist; and, on Unix-like systems, less likely to contain
    a .git entry (though a git with security updates should refuse
    to take any configuration from such a repository unless it is owned
    by the user).

    Due to a combination of other measures that harden against
    malicious or unusual contents (especially setting GIT_DIR), the
    most significant benefit of this change is to fix the problem that
    a nonexistent temp dir would prevent the command from succeeding.

    The main way that could happen is if TMPDIR on Unix-like systems,
    or TMP or TEMP on Windows, is set to an incorrect value.
    Because these variables are sometimes reasonable to customize for
    specific purposes, it is plausible for them to be set to incorrect
    values by accident.

    Except on Windows, this always uses / as the CWD for the
    subprocess.

    On Windows, we use the Windows directory (usually C:\Windows)
    rather than the root of the system drive (usually C:\), because:

    • We are currently obtaining this information from environment
      variables, and it is possible for our own parent process to pass
      down an overly sanitized environment.

    Although this can be so sanitized we cannot find the Windows
    directory, this is less likely to occur than being unable to find
    the root of the system drive.

    This due to moderately broad awareness that the SystemRoot
    environment variable (which, somewhat confusingly, holds the path
    of the Windows directory, not the root of the system drive)
    should be preserved even when clearing most other variables.

    Some libraries will even automatically preserve SystemRoot when
    clearing others or restore it. For example:

  • Under the current behavior of env::temp_dir(), which is now a
    fallback if we cannot determine the Windows directory, we already
    fall back to the Windows directory evenutally, if temp dir
    related environment variables are also unset.

    This is because env::temp_dir() usually calls GetTempDir2 in
    the Windows API, which implements that fallback behavior (after
    first trying the user's user profile directory).

    Avoiding adding yet another place to fall back to that would not
    otherwise be attempted slightly decreases behavioral complexity,
    and there is no reason to think a directory like C:\ would work
    when a directory like C:\Windows doesn't.

  • The root of the system drive on a Windows system usually permits
    limited user accounts to create new directories there, so a
    directory like C:\ on Windows actually has most of the
    disadvantages of a location like /tmp on a Unix-like system.

    This is actually a much less significant reason to prefer a
    directory like C:\Windows to a directory like C:\ than it
    might seem. After all, if C:\.git exists and and git uses it
    when run from C:\, then git would usually also use it when
    run from C:\Windows (and from numerous other locations)!

    However, the reason there is still a small reason to prefer a
    location like C:\Windows to a location like C:\ is that, if a
    system has a vulnerable git but a user or system administrator
    has sought to work around it by listing C:\ in
    GIT_CEILING_DIRECTORIES, then that may keep git from
    traversing upward into C:\, but it would not keep C:\ from
    being used if that is where we already are.

    An even more significant reason this motivation is a minor one is
    that the other measures we are taking, including setting
    GIT_DIR, should be sufficient to avoid at least the security
    dimension of the problem, which arises from actually using the
    configuration from a repo that is discovered.

  • The user profile directory may be more deeply nested.

  • The user profile directory may sometimes be on slow network
    storage when the discovered Windows directory is not.

  • In some situations, the user profile directory does not actually
    exist, or does not exist yet.

  • Overly sanitized environments are more likely to lack the
    USERPROFILE vairable than the SystemRoot variable.

  • Users may occasionally choose to have their entire user profile
    directory be a Git repository.

  • It's no easier to avoid the problem of using C:\.git in a user
    profile directory than in C:\Windows: they're usually both under
    C:\, and are both not the same as C:\. (If the user profile
    directory is a repository, then that will avoid that problem, yet
    be its own problem, if not for other measures that prevent both.)

  • If the git command is an old and unpatched vulnerable version
    in which safe.directory is not yet implemented, or in which
    GHSA-j342-m5hw-rr3v
    or other vulnerabilities where git would perform operations on
    untrusted local repositories owned by other users are unpatched,
    then a .git subdirectory of a shared /tmp or /tmp-like
    directory could be created by another account, and its local
    configuration would still have been used. (This is not a bug in
    gitoxide per se; having vulnerable software installed that other
    software may use is inherently insecure. But it is nice to offer
    a small amount of protection against this when readily feasible.)

  • If the /tmp-like location is a Git repository owned by the
    current user, then its local configuration would have been used.

  • https:/dotnet/docs/issues/41193

  • https:/python/cpython/pull/95486#issuecomment-1881469554

  • https:/python/cpython/pull/95486#issuecomment-1882134234

  • Parsing is more reliable for paths containing unusual characters,
    because -z/--null causes all paths to be output literally.

    Previously, " characters were trimmed from the ends, but this
    would not always extract a correct path, because when a path
    contains characters that cause git to enclose it in double
    quotes, those characters are usually represented in a symbolic
    form, usually with \ escapes.

    In some scenarios, such as usually on Windows when the escaped
    character is itself a \ and not in the leading position, the
    mangled path would be usable, but more often it would not.

  • The volume of output is less, because --name-only casues values
    not to be included in the output.

  • The combination of -z/--null and --name-only makes the
    output format simpler, and the parsing logic is accordingly
    simpler.

Commit Statistics
  • 56 commits contributed to the release.
  • 14 days passed between releases.
  • 3 commits were understood as conventional.
  • 0 issues like '(#ID)' were seen in commit messages
Commit Details
view details
  • Uncategorized
    • Prepare changelogs prior to release. (c759819)
    • Merge pull request #​1569 from EliahKagan/config-origin-naming (3cf9694)
    • Rename to GIT_HIGHEST_SCOPE_CONFIG_PATH (0672576)
    • Merge pull request #​1568 from EliahKagan/config-origin-next (adbaa2a)
    • Rename EXE_INFO to something that probably captures its contents better. (dd2d666)
    • Run cargo fmt (b11f7db)
    • Make EXE_NAME a const too (fb0b6d8)
    • Make NULL_DEVICE a const, rather than a static item (9917d47)
    • Put first_file_from_config_with_origin test with related ones (57e9a6f)
    • Fix indentation nit (7cd20bb)
    • Merge pull request #​1567 from EliahKagan/config-origin (dd65e7b)
    • Improve structure of exe_info tests (5ac5f74)
    • Clarify comment about where we run git from (5200184)
    • Test no local scope with empty system config (6160a83)
    • Don't set/change ceiling directories (2bce0d2)
    • Explore also setting a ceiling directory (073e277)
    • Fix misstatement of Windows directory rationale (4e936bc)
    • Unset a couple env vars just in case (8f6d39d)
    • Simplify the new comments (b827813)
    • Explain why we run git from a different directory (7fa5e35)
    • Small clarity tweaks (598c487)
    • Fix os::windows error on non-Windows (1305114)
    • Refactor for readability; clarify comments (ab0dcc1)
    • Fix unused import on non-Windows systems (8472447)
    • Don't require usable temp dir to get installation config (f70b904)
    • Explain why we don't just use --system (29c6cca)
    • Explain why we don't just use --show-scope (f35e44c)
    • Fix a test name for consistency (15e7b67)
    • Add another broken temp test (c80d562)
    • Extract nonexistent directory logic to a test helper struct (e60540f)
    • Maybe slightly decrease risk of test precondition check failure (56dab13)
    • Adjust some test code for clarity (5c1b4c0)
    • Check env::temp_dir() in both tests that set temp vars (79af259)
    • Clarify assert and expect messages (703f882)
    • Test EXE_INFO no local config even if temp dir doesn't exist (60465a5)
    • Slightly improve quality of test failure messages (9641660)
    • Set GIT_WORK_TREE along with GIT_DIR, to avoid confusion (5723077)
    • More robustly ensure "installation" config is not local (7280a2d)
    • Check that the test affects env::temp_dir() as desired (15cec4e)
    • Fix bug in new test where temp dir should be a repo (744bb38)
    • Test EXE_INFO no local config even if temp dir is a repo (287f267)
    • Code formatting (65d5151)
    • Fix EXE_INFO no local scope test for macOS (49e0715)
    • Add generated archive for local_config.sh (fd065ac)
    • Test that EXE_INFO never has local scope config (5a300e6)
    • Make EXE_INFO testable and add a basic test for it (1ee98bf)
    • Reorder gix_path::env::git tests to match order in code (ccd0401)
    • Extract git_cmd helper for EXE_INFO (de2f35f)
    • Parse installation config path more robustly (650a1b5)
    • Comment Git version compatibility for EXE_INFO (9df57aa)
    • Merge pull request #​1557 from Byron/merge-base (649f588)
    • Allow empty-docs (beba720)
    • Merge branch 'global-lints' (37ba461)
    • Workspace Clippy lint management (2e0ce50)
    • Merge pull request #​1546 from nyurik/semilocons (f992fb7)
    • Add missing semicolons (ec69c88)

v0.10.10: gix-path v0.10.10

Compare Source

A maintenance release without user-facing changes.

Commit Statistics
  • 6 commits contributed to the release over the course of 12 calendar days.
  • 35 days passed between releases.
  • 0 commits were understood as conventional.
  • 0 issues like '(#ID)' were seen in commit messages
Commit Details
view details
  • Uncategorized
    • Prepare changelogs prior to release (0f25841)
    • Merge pull request #​1523 from martinvonz/push-xmsuurxprnnw (83c9de0)
    • Remove --system from git config call as it fails on MacOS (6b1c243)
    • Run git config -l in temp dir when looking up system config (20ef4e9)
    • Merge branch 'push-ysnqkzlzwuwq' (e2c747d)
    • Don't show console on Windows (087594c)

Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants