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

Fix Windows environment variable upcasing bug #1650

Merged
merged 4 commits into from
Sep 7, 2023

Conversation

EliahKagan
Copy link
Contributor

@EliahKagan EliahKagan commented Sep 7, 2023

Fixes #1646

This fixes the bug I inadvertently introduced in #1636 where all environment variables' names are set upper-case on Windows.

It uses a simple hand-rolled context manager to patch the NoDefaultCurrentDirectoryInExePath variable, instead of unittest.mock.patch.dict. The latter was setting unrelated environment variables to the original (same) values via os.environ, and as a result, their names were all converted to upper-case on Windows. This is the intended behavior of os.environ on Windows, at least in CPython, per python/cpython#73010 and python/cpython#101754, but I had not been thinking of this, and more importantly I was not aware that unittest.mock.patch.dict effectively writes all items to the mapping when it unpatches, including items that had not been listed for patching.

Because only environment variables that are actually set through os.environ have their names upcased, the only variable whose name should be upcased now is NoDefaultCurrentDirectoryInExePath, which should be fine. (It has a single established use/meaning in Windows, where it's treated case-insensitively as environment variables in Windows usually are.)


The actual fix here is pretty simple, but robustly testing it is tricky. One pitfall in testing it remains unaddressed at this point: Either the bug doesn't affect Cygwin builds of Python (linking cygwin1.dll), or is_win evaluates to false in the test-cygwin.yml workflows, so the project's current CI cannot verify the fix. Notice, for example, that the first two commits (d88372a and 7296e5c) show as passing all tests, even though they should show as failing on Windows. I am unsure if that should block this PR or not, since it seems like this sort of thing might actually be common.

I could make the test run on more platforms than Windows, but I don't think that would be more robust, because on other systems it would effectively just be testing that the Python implementation of os.environ works as expected on non-Windows systems. Furthermore, the important test logic would differ depending on the value of is_win, so if the Cygwin workflow has is_win as false, then it would only create the false impression that CI was verifying the fix.

It might be possible to improve the situation in the CI workflows themselves. But I think that would take longer than it might be good to wait on fixing this bug, since this bug currently prevents users who rely on case-sensitive environment variables from upgrading far enough to receive fixes for either CVE-2023-40590 (3.1.33) or CVE-2023-41040 (3.1.35, forthcoming).

I have verified the fix locally. That test failure is from before the fix in c7fad20. It is taken from 7296e5c.

Both tests shown there pass starting in the third commit (c7fad20), as expected, and continue to pass in the fourth commit (eebdb25). Due to the new test's use of the new "fixture" script env_case.py, together with how the official installation instructions do not create a true editable install, if python setup.py install was how installation was done, and it was done prior to checking out the fix, then python setup.py install has to be run again for the "fixture" script to get the current code when it runs import git. I considered going back to the previous way that doesn't execute a separate script file, but I think that code may be harder to understand for someone who doesn't already know how the test works.

This uses a simple hand-rolled context manager to patch the
NoDefaultCurrentDirectoryInExePath variable, instead of
unittest.mock.patch.dict. The latter set unrelated environment
variables to the original (same) values via os.environ, and as a
result, their names were all converted to upper-case on Windows.

Because only environment variables that are actually set through
os.environ have their names upcased, the only variable whose name
should be upcased now is NoDefaultCurrentDirectoryInExePath, which
should be fine (it has a single established use/meaning in Windows,
where it's treated case-insensitively as environment variables in
Windows *usually* are).
@EliahKagan EliahKagan changed the title Add test for Windows env var upcasing regression Fix Windows env var upcasing regression Sep 7, 2023
@EliahKagan EliahKagan changed the title Fix Windows env var upcasing regression Fix Windows environment variable upcasing regression Sep 7, 2023
@EliahKagan EliahKagan changed the title Fix Windows environment variable upcasing regression Fix Windows environment variable upcasing bug Sep 7, 2023
@Byron Byron added this to the v3.1.35 - Bugfixes milestone Sep 7, 2023
@irwand
Copy link

irwand commented Sep 7, 2023

This works for single thread, but because it temporarily change os.environ, this could cause unexpected race-condition with other threads that are doing something relying on os.environ. This bug will be even harder to detect and catch.

One of the best way to fix this is to re-implement shutil.which() that does not prepend current cwd into the PATH when looking for git, and then just use the git path we found directly. This way we don't cause unexpected side effect by temporarily changing os.environ

Copy link
Member

@Byron Byron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for contributing a fix for a fix for the CVE! It's much appreciated, particularly because this is a strange issue and you even found a way to add a regression test.

Regarding CI, if you have interest in adding a way to improve CI coverage so that this kind of bug would have been caught, I'd definitely appreciate another PR.

PS: I would assign 'legendary' status to your PRs - they make the impression of being a work-log of sorts, maybe one that is part of your workflow or organize work even. Amazing.

git/util.py Show resolved Hide resolved
git/util.py Show resolved Hide resolved
test/test_git.py Show resolved Hide resolved
test/test_git.py Show resolved Hide resolved
@EliahKagan
Copy link
Contributor Author

@irwand Yes, in #1636 I had not really thought carefully enough about the situations in which a data race on os.environ might occur. Per #1052 (comment), GitPython is not thread-safe, with some concurrent operations such as chdir being unsafe while GitPython code is executing. However, a project that uses GitPython and separately mutates os.environ for a reason unrelated to GitPython should ideally be free of data races, and likely was free of them (unless also doing chdir) prior to #1636.

Although reimplementing shutil.which is one option, I would lean toward a variation of the approach I took in #1636: instead of patching os.environ or otherwise changing environment variables for the current process, use another layer of subprocess indirection (on Windows only), so GitPython creates a subprocess that sets NoDefaultCurrentDirectoryInExePath and then itself creates the git subprocess. I'm not really sure what is better, though.

I think it's worthwhile to merge this PR in order to fix the immediate problem in #1646. But a new issue should probably be opened for the race condition that you have rightly identified. I don't know if you'd prefer to open it or if I should.

@EliahKagan EliahKagan marked this pull request as ready for review September 7, 2023 13:20
@irwand
Copy link

irwand commented Sep 7, 2023

I really appreciate the fix and have no objection to merging this in 👍 .. this will allow us to continue upgrading to newer gitpython :-) . The os.environ side effect is there, but not sure practically how bad that would be. Really if the industry already identifies that including cwd when looking for executables is a bad idea, maybe NoDefaultCurrentDirectoryInExePath should just be default. Feel free to open the race condition issue. From my point of view this is good enough and the race condition issue is somewhat low priority. Thank you again!

@Byron Byron merged commit 09e1b3d into gitpython-developers:main Sep 7, 2023
7 checks passed
@Byron
Copy link
Member

Byron commented Sep 7, 2023

The new release with various fixes is now available: https://pypi.org/project/GitPython/3.1.35/

@EliahKagan EliahKagan deleted the envcase branch September 7, 2023 13:52
renovate bot referenced this pull request in allenporter/flux-local Sep 8, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [GitPython](https://togithub.com/gitpython-developers/GitPython) |
`==3.1.34` -> `==3.1.35` |
[![age](https://developer.mend.io/api/mc/badges/age/pypi/GitPython/3.1.35?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/GitPython/3.1.35?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/GitPython/3.1.34/3.1.35?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/GitPython/3.1.34/3.1.35?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>gitpython-developers/GitPython (GitPython)</summary>

###
[`v3.1.35`](https://togithub.com/gitpython-developers/GitPython/releases/tag/3.1.35):
- a fix for CVE-2023-41040

[Compare
Source](https://togithub.com/gitpython-developers/GitPython/compare/3.1.34...3.1.35)

#### What's Changed

- Bump actions/checkout from 3 to 4 by
[@&#8203;dependabot](https://togithub.com/dependabot) in
[https://github.com/gitpython-developers/GitPython/pull/1643](https://togithub.com/gitpython-developers/GitPython/pull/1643)
- Fix 'Tree' object has no attribute '\_name' when submodule path is
normal path by [@&#8203;CosmosAtlas](https://togithub.com/CosmosAtlas)
in
[https://github.com/gitpython-developers/GitPython/pull/1645](https://togithub.com/gitpython-developers/GitPython/pull/1645)
- Fix CVE-2023-41040 by
[@&#8203;facutuesca](https://togithub.com/facutuesca) in
[https://github.com/gitpython-developers/GitPython/pull/1644](https://togithub.com/gitpython-developers/GitPython/pull/1644)
- Only make config more permissive in tests that need it by
[@&#8203;EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1648](https://togithub.com/gitpython-developers/GitPython/pull/1648)
- Added test for PR
[#&#8203;1645](https://togithub.com/gitpython-developers/GitPython/issues/1645)
submodule path by
[@&#8203;CosmosAtlas](https://togithub.com/CosmosAtlas) in
[https://github.com/gitpython-developers/GitPython/pull/1647](https://togithub.com/gitpython-developers/GitPython/pull/1647)
- Fix Windows environment variable upcasing bug by
[@&#8203;EliahKagan](https://togithub.com/EliahKagan) in
[https://github.com/gitpython-developers/GitPython/pull/1650](https://togithub.com/gitpython-developers/GitPython/pull/1650)

#### New Contributors

- [@&#8203;CosmosAtlas](https://togithub.com/CosmosAtlas) made their
first contribution in
[https://github.com/gitpython-developers/GitPython/pull/1645](https://togithub.com/gitpython-developers/GitPython/pull/1645)
- [@&#8203;facutuesca](https://togithub.com/facutuesca) made their first
contribution in
[https://github.com/gitpython-developers/GitPython/pull/1644](https://togithub.com/gitpython-developers/GitPython/pull/1644)

**Full Changelog**:
gitpython-developers/GitPython@3.1.34...3.1.35

</details>

---

### Configuration

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

🚦 **Automerge**: Enabled.

♻ **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.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/allenporter/flux-local).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi44My4wIiwidXBkYXRlZEluVmVyIjoiMzYuODMuMCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
otc-zuul bot pushed a commit to opentelekomcloud-infra/eyes_on_docs that referenced this pull request Sep 11, 2023
Bump gitpython from 3.1.32 to 3.1.35

Bumps gitpython from 3.1.32 to 3.1.35.

Release notes
Sourced from gitpython's releases.

3.1.35 - a fix for CVE-2023-41040
What's Changed

Bump actions/checkout from 3 to 4 by @​dependabot in gitpython-developers/GitPython#1643
Fix 'Tree' object has no attribute '_name' when submodule path is normal path by @​CosmosAtlas in gitpython-developers/GitPython#1645
Fix CVE-2023-41040 by @​facutuesca in gitpython-developers/GitPython#1644
Only make config more permissive in tests that need it by @​EliahKagan in gitpython-developers/GitPython#1648
Added test for PR #1645 submodule path by @​CosmosAtlas in gitpython-developers/GitPython#1647
Fix Windows environment variable upcasing bug by @​EliahKagan in gitpython-developers/GitPython#1650

New Contributors

@​CosmosAtlas made their first contribution in gitpython-developers/GitPython#1645
@​facutuesca made their first contribution in gitpython-developers/GitPython#1644

Full Changelog: gitpython-developers/[email protected]
3.1.34 - fix resource leaking
What's Changed

util: close lockfile after opening successfully by @​skshetry in gitpython-developers/GitPython#1639

New Contributors

@​skshetry made their first contribution in gitpython-developers/GitPython#1639

Full Changelog: gitpython-developers/[email protected]
v3.1.33 - with security fix
What's Changed

WIP Quick doc by @​LeoDaCoda in gitpython-developers/GitPython#1608
Partial clean up wrt mypy and black by @​bodograumann in gitpython-developers/GitPython#1617
Disable merge_includes in config writers by @​bodograumann in gitpython-developers/GitPython#1618
feat: full typing for "progress" parameter in Repo class by @​madebylydia in gitpython-developers/GitPython#1634
Fix CVE-2023-40590 by @​EliahKagan in gitpython-developers/GitPython#1636
#1566 Creating a lock now uses python built-in "open()" method to work arou… by @​HageMaster3108 in gitpython-developers/GitPython#1619

New Contributors

@​LeoDaCoda made their first contribution in gitpython-developers/GitPython#1608
@​bodograumann made their first contribution in gitpython-developers/GitPython#1617
@​EliahKagan made their first contribution in gitpython-developers/GitPython#1636
@​HageMaster3108 made their first contribution in gitpython-developers/GitPython#1619

Full Changelog: gitpython-developers/[email protected]



Commits

c8e303f prepare next release
09e1b3d Merge pull request #1650 from EliahKagan/envcase
8017421 Merge pull request #1647 from CosmosAtlas/master
fafb4f6 updated docs to better describe testing procedure with new repo
9da24d4 add test for submodule path not owned by submodule case
eebdb25 Eliminate duplication of git.util.cwd logic
c7fad20 Fix Windows env var upcasing regression
7296e5c Make test helper script a file, for readability
d88372a Add test for Windows env var upcasing regression
11839ab Merge pull request #1648 from EliahKagan/file-protocol
Additional commits viewable in compare view




Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

@dependabot rebase will rebase this PR
@dependabot recreate will recreate this PR, overwriting any edits that have been made to it
@dependabot merge will merge this PR after your CI passes on it
@dependabot squash and merge will squash and merge this PR after your CI passes on it
@dependabot cancel merge will cancel a previously requested merge and block automerging
@dependabot reopen will reopen this PR if it is closed
@dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
@dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
@dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
@dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
@dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the Security Alerts page.

Reviewed-by: Vladimir Vshivkov
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

CVE-2023-40590 fix capitalized all environment variables on Windows
3 participants