Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix CVE-2023-41040#1644

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged

Conversation

facutuesca
Copy link
Contributor

This change adds a check during reference resolving to see if the requested reference is inside the current repository folder. If it's ouside, it raises an exception.

This fixesCVE-2023-41040, which allows an attacker to access files outside the repository's directory.

Thiscloses#1638.

Copy link
Member

@ByronByron left a comment

Choose a reason for hiding this comment

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

Thanks for the initiative! Could you add some tests that fail if the change is not applied?
Thanks

@facutuesca
Copy link
ContributorAuthor

Thanks for the initiative! Could you add some tests that fail if the change is not applied? Thanks

Done!

# Make path absolute, resolving any symlinks, and check that we are still
# inside the repository
full_ref_path = Path(repodir, str(ref_path)).resolve()
if Path(repodir).resolve() not in full_ref_path.parents:
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifPath(repodir).resolve()notinfull_ref_path.parents:
ifnotfull_ref_path.is_relative_to(Path(repodir).absolute()):

Usingabsolute() instead ofresolve() just in case the repodir is a symlink.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Why not resolve the symlink?

Copy link
Contributor

Choose a reason for hiding this comment

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

If repodir is a symlink, then full_ref_path will be able to escape the repodir path.

For example, if repodir is a symlink to/home/secrets/, then full_ref_path can create a symlink to/home/secrets/myscecrets, being able to skip the check.

Copy link
ContributorAuthor

@facutuescafacutuescaSep 5, 2023
edited
Loading

Choose a reason for hiding this comment

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

But repodir is not given by the user, rather it's computed using:

repodir=_git_dir(repo,ref_path)

which returns (if I understand it correctly) the repo's.git folder. Is there a scenario where that folder can be a symlink? Or rather, a malicious symlink?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I guess my point is: if your.git directory is a symlink to/home/secrets,GitPythonwill have access to everything under/home/secrets, so no point in protecting against that in this very specific function

@ByronByron requested a review fromemptySeptember 6, 2023 05:32
Copy link
Member

@ByronByron left a comment

Choose a reason for hiding this comment

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

Thanks for taking a look into this!

I have come up with a couple of suggestions and hope they make sense.

with open(os.path.join(repodir, str(ref_path)), "rt", encoding="UTF-8") as fp:
# Make path absolute, resolving any symlinks, and check that we are still
# inside the repository
full_ref_path = Path(repodir, str(ref_path)).resolve()
Copy link
Member

Choose a reason for hiding this comment

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

I think this will slow down each read of a loose ref, and maybe that can be avoided?
References mentioned in a symbolic ref are never absolute, and can be rejected on that ground. Then, when determined relative, one should normalize the../ away to check if it would break out. Sorefs/../foo would be fine, butrefs/../foo/../../bar would not be. All this can happen without resolving symlinks.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I replaced the calls toresolve() withos.path.abspath, which normalizes.. but does not resolve symlinks.

@@ -171,7 +172,14 @@ def _get_ref_info_helper(
tokens: Union[None, List[str], Tuple[str, str]] = None
repodir = _git_dir(repo, ref_path)
try:
with open(os.path.join(repodir, str(ref_path)), "rt", encoding="UTF-8") as fp:
Copy link
Member

Choose a reason for hiding this comment

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

When looking at howgitoxide (andgit) do it I noticed that this could be much simpler.
Ref-names can't be anything they want, they are very limited in what's allowed and what is not (seethis validation code as reference).

It would be enough to reject anyref_path that has a parent-dir component in it.

What do you think?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Ah yeah you're right! I fixed it so that now it only checks for.. in theref_path

This change adds a check during reference resolving to see if itcontains an up-level reference ('..'). If it does, it raises anexception.This fixesCVE-2023-41040, which allows an attacker to access filesoutside the repository's directory.
Copy link
Member

@ByronByron 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 CVE-fix!

Kurt-von-Laven, facutuesca, xesf, and EliahKagan reacted with hooray emoji
@ByronByron merged commit74e55ee intogitpython-developers:mainSep 7, 2023
@facutuescafacutuesca deleted the fix-cve-2023-41040 branchSeptember 7, 2023 06:26
@EliahKaganEliahKagan mentioned this pull requestSep 7, 2023
bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull requestSep 7, 2023
… via SR 1109413https://build.opensuse.org/request/show/1109413by user dgarcia + anag+factory- AddCVE-2023-41040.patch to fix directory traversal attack  vulnerability gh#gitpython-developers/GitPython#1644  bsc#1214810- Update _service to use manualrun, disabledrun is deprecated now.- Update to version 3.1.34.1693646983.2a2ae77:  * prepare patch release  * util: close lockfile after opening successfully  * update instructions for how to create a release  * prepare for next release  * Skip now permanently failing test with note on how to fix it  * Don't check form of version number  * Add a unit test forCVE-2023-40590  * FixCVE-2023-40590  * feat: full typing for "progress" parameter  * Creating a lock now uses python built-in "open()" method to work around docker virtiofs issue  * Disable merge_includes in config writers  * Apply straight-forward typing fixes
renovatebot referenced this pull request in allenporter/flux-localSep 8, 2023
[![MendRenovate](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 forCVE-2023-41040[CompareSource](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 isnormal 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)- FixCVE-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 theirfirst 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 firstcontribution 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 therebase/retry checkbox.🔕 **Ignore**: Close this PR and you won't be reminded about this updateagain.---- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, checkthis box---This PR has been generated by [MendRenovate](https://www.mend.io/free-developer-tools/renovate/). Viewrepository 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-zuulbot pushed a commit to opentelekomcloud-infra/eyes_on_docs that referenced this pull requestSep 11, 2023
Bump gitpython from 3.1.32 to 3.1.35Bumps gitpython from 3.1.32 to 3.1.35.Release notesSourced from gitpython's releases.3.1.35 - a fix forCVE-2023-41040What's ChangedBump actions/checkout from 3 to 4 by @​dependabot ingitpython-developers/GitPython#1643Fix 'Tree' object has no attribute '_name' when submodule path is normal path by @​CosmosAtlas ingitpython-developers/GitPython#1645FixCVE-2023-41040 by @​facutuesca ingitpython-developers/GitPython#1644Only make config more permissive in tests that need it by @​EliahKagan ingitpython-developers/GitPython#1648Added test for PR #1645 submodule path by @​CosmosAtlas ingitpython-developers/GitPython#1647Fix Windows environment variable upcasing bug by @​EliahKagan ingitpython-developers/GitPython#1650New Contributors@​CosmosAtlas made their first contribution ingitpython-developers/GitPython#1645@​facutuesca made their first contribution ingitpython-developers/GitPython#1644Full Changelog: gitpython-developers/GitPython@3.1.34...3.1.353.1.34 - fix resource leakingWhat's Changedutil: close lockfile after opening successfully by @​skshetry ingitpython-developers/GitPython#1639New Contributors@​skshetry made their first contribution ingitpython-developers/GitPython#1639Full Changelog: gitpython-developers/GitPython@3.1.33...3.1.34v3.1.33 - with security fixWhat's ChangedWIP Quick doc by @​LeoDaCoda ingitpython-developers/GitPython#1608Partial clean up wrt mypy and black by @​bodograumann ingitpython-developers/GitPython#1617Disable merge_includes in config writers by @​bodograumann ingitpython-developers/GitPython#1618feat: full typing for "progress" parameter in Repo class by @​madebylydia ingitpython-developers/GitPython#1634FixCVE-2023-40590 by @​EliahKagan ingitpython-developers/GitPython#1636#1566 Creating a lock now uses python built-in "open()" method to work arou… by @​HageMaster3108 ingitpython-developers/GitPython#1619New Contributors@​LeoDaCoda made their first contribution ingitpython-developers/GitPython#1608@​bodograumann made their first contribution ingitpython-developers/GitPython#1617@​EliahKagan made their first contribution ingitpython-developers/GitPython#1636@​HageMaster3108 made their first contribution ingitpython-developers/GitPython#1619Full Changelog: gitpython-developers/GitPython@3.1.32...3.1.33Commitsc8e303f prepare next release09e1b3d Merge pull request #1650 from EliahKagan/envcase8017421 Merge pull request #1647 from CosmosAtlas/masterfafb4f6 updated docs to better describe testing procedure with new repo9da24d4 add test for submodule path not owned by submodule caseeebdb25 Eliminate duplication of git.util.cwd logicc7fad20 Fix Windows env var upcasing regression7296e5c Make test helper script a file, for readabilityd88372a Add test for Windows env var upcasing regression11839ab Merge pull request #1648 from EliahKagan/file-protocolAdditional commits viewable in compare viewDependabot 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 optionsYou 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
@doc-sheet
Copy link

@facutuesca,@Byron, wait but issue is still there.
Because of how os.path.join works it is possible toexploit it with just a passing absolute path.

Like

import gitr = git.Repo(".")r.commit("/dev/null")
Byron and EliahKagan reacted with thumbs up emojistsewd reacted with confused emoji

@facutuesca
Copy link
ContributorAuthor

facutuesca commentedSep 19, 2023
edited
Loading

@facutuesca,@Byron, wait but issue is still there. Because of how os.path.join works it is possible toexploit it with just a passing absolute path.

@doc-sheet Ah I see. Would resolvingrepodir to an absolute path before callingos.path.join be enough to fix it?

abs_repodir=os.path.abspath(repodir)withopen(os.path.join(abs_repodir,str(ref_path)),"rt",encoding="UTF-8")asfp:

@Byron
Copy link
Member

This would certainly be feasible if the absolute version of a repository path is stored on the repository itself as a sort of cache.

It's definitely something that would need addressing.

CC@EliahKagan

@EliahKagan
Copy link
Member

EliahKagan commentedSep 20, 2023
edited
Loading

Couldn't theref_path check in_get_ref_info_helper that this PR added just be made more robust, so it rejects non-relative paths, as well as those that contain..? Currently we have:

if".."instr(ref_path):
raiseValueError(f"Invalid reference '{ref_path}'")

I think the new cases to reject include absolute paths, but also paths that are neither absolute nor relative. The latter is possible on Windows, where you can have a path likeC:a that refers toa in the "current directory" on theC: driveeven whenC: is not the current drive (see the note onthis page), as well as a path like/a or\a that refers toa in the root of the current drive.

Neither is consistently considered absolute by the Python standard library. Neitheros.path.isabs nor thepathlib.Path.is_absolute method consider paths likeC: orC:a absolute. Interestingly, they disagree on Windows about/a and\a. I don't mean the/ and\ versions are treated differently--those are treated the same, that's not the issue. Rather,pathlib.Path is aware such paths are not, in the strictest sense, absolute paths on Windows, whileos.path.isabs is treats them as absolute. Paths likeC: orC:a, as well as those like/a or\a, have joining behavior similar to that whichdoc-sheet pointed out true absolute paths have.

I am reminded ofsome code I wrote a few months ago, in a different context but also about avoiding directory traversal:

path=Path(name)ifpath.is_absolute():# Absolute paths can extract outside the target directory.raisezipfile.BadZipFile(f'archive has absolute path:{name!r}')ifpath.rootorpath.drive:# Non-relative non-absolute paths on Windows can do the same.raisezipfile.BadZipFile(f'archive has non-relative path:{name!r}')if'..'inname:# A ".." component, or "...", "....", etc. on some systems, can# traverse upward. Because we know what is reasonable in a USC# archive, broadly denying paths with ".." anywhere is okay.raisezipfile.BadZipFile(f'archive has name containing "..":{name!r}')

That would have to be adapted slightly--for example, we are not raisingBadZipFile--but I think something like that could be done.

doc-sheet reacted with thumbs up emoji

@doc-sheet
Copy link

Would resolving repodir to an absolute path before calling os.path.join be enough to fix it?

I don't think so. As long as second+ argument to os.path.join starts from/ (i don't know about windows) it will replace everything before it.

facutuesca reacted with thumbs up emoji

@doc-sheet
Copy link

Maybe there is across-platform solution with commonpath / Path.is_relative_to

def is_safe_path(basedir, path, follow_symlinks=True):    # resolves symbolic links    if follow_symlinks:        matchpath = os.path.realpath(path)    else:        matchpath = os.path.abspath(path)    return basedir == os.path.commonpath((basedir, matchpath))
EliahKagan reacted with thumbs up emoji

@facutuesca
Copy link
ContributorAuthor

facutuesca commentedSep 20, 2023
edited
Loading

@EliahKagan@doc-sheet@Byron What about implementing the rules inhttps://git-scm.com/docs/git-check-ref-format/ and using them to check reference names? It looks like rules 3, 4, 6 and 10 would cover the problematic behaviors we're talking about, plus more:

(3). They cannot have two consecutive dots.. anywhere.
(4). They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177DEL), space, tilde~, caret^,or colon: anywhere.
(6). They cannot begin or end with a slash/ or contain multiple consecutive slashes
(10). They cannot contain a\.

EliahKagan, doc-sheet, and Byron reacted with thumbs up emoji

@Byron
Copy link
Member

Thanks everyone!

if".."instr(ref_path):
raiseValueError(f"Invalid reference '{ref_path}'")

It seems the above function could be upgraded to do more complete validation similar tohttps://git-scm.com/docs/git-check-ref-format/ .

gitoxide implements thishere, and was itself written based ongit's validation code - maybe it can be useful here when implementing a python version.

EliahKagan reacted with thumbs up emoji

@facutuesca
Copy link
ContributorAuthor

@Byron@doc-sheet@EliahKagan I have created a PR for this here:#1672

EliahKagan, Byron, and doc-sheet reacted with thumbs up emoji

@EliahKagan
Copy link
Member

EliahKagan commentedSep 22, 2023
edited
Loading

By the way, for the benefit of anyone who comes along to read this, the example in#1644 (comment) may not look like it shows anything, but this is because reading from/dev/null completes immediately and the resulting exception and traceback from GitPython doesn't obviously indicate that this happened. If a path like/dev/zero or/dev/random is passed, it keeps reading and reading, and using system resources, etc. (Thus, you maynot want to try that on your system, at least if you're not prepared to kill the process.)

So in a situation where an application that uses GitPython exposes queries on refs in specific local repositories without the intention of allowing reads from elsewhere in the filesystem, using an absolute path rather than a relative one with.. components provided another way to exploit the vulnerability that was not prevented by the original patch. (At least that is my understanding of the situation.)

Byron and doc-sheet reacted with thumbs up emoji

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@stsewdstsewdstsewd left review comments

@ByronByronByron approved these changes

@emptyemptyAwaiting requested review from empty

Assignees
No one assigned
Labels
None yet
Development

Successfully merging this pull request may close these issues.

CVE-2023-41040: Blind local file inclusion
5 participants
@facutuesca@doc-sheet@Byron@EliahKagan@stsewd

[8]ページ先頭

©2009-2025 Movatter.jp