)]}'
{
  "commit": "58325b93c5b6212697b088371809e9948fee8052",
  "tree": "a31cc7248c341123025227a6c4d0053a8664fe7f",
  "parents": [
    "0227130244c007870c106fc613903d078730e45c"
  ],
  "author": {
    "name": "Taylor Blau",
    "email": "me@ttaylorr.com",
    "time": "Tue Jan 24 19:43:45 2023 -0500"
  },
  "committer": {
    "name": "Junio C Hamano",
    "email": "gitster@pobox.com",
    "time": "Tue Jan 24 16:52:16 2023 -0800"
  },
  "message": "t5619: demonstrate clone_local() with ambiguous transport\n\nWhen cloning a repository, Git must determine (a) what transport\nmechanism to use, and (b) whether or not the clone is local.\n\nSince f38aa83f9a (use local cloning if insteadOf makes a local URL,\n2014-07-17), the latter check happens after the remote has been\ninitialized, and references the remote\u0027s URL instead of the local path.\nThis is done to make it possible for a `url.\u003cbase\u003e.insteadOf` rule to\nconvert a remote URL into a local one, in which case the `clone_local()`\nmechanism should be used.\n\nHowever, with a specially crafted repository, Git can be tricked into\nusing a non-local transport while still setting `is_local` to \"1\" and\nusing the `clone_local()` optimization. The below test case\ndemonstrates such an instance, and shows that it can be used to include\narbitrary (known) paths in the working copy of a cloned repository on a\nvictim\u0027s machine[^1], even if local file clones are forbidden by\n`protocol.file.allow`.\n\nThis happens in a few parts:\n\n 1. We first call `get_repo_path()` to see if the remote is a local\n    path. If it is, we replace the repo name with its absolute path.\n\n 2. We then call `transport_get()` on the repo name and decide how to\n    access it. If it was turned into an absolute path in the previous\n    step, then we should always treat it like a file.\n\n 3. We use `get_repo_path()` again, and set `is_local` as appropriate.\n    But it\u0027s already too late to rewrite the repo name as an absolute\n    path, since we\u0027ve already fed it to the transport code.\n\nThe attack works by including a submodule whose URL corresponds to a\npath on disk. In the below example, the repository \"sub\" is reachable\nvia the dumb HTTP protocol at (something like):\n\n    http://127.0.0.1:NNNN/dumb/sub.git\n\nHowever, the path \"http:/127.0.0.1:NNNN/dumb\" (that is, a top-level\ndirectory called \"http:\", then nested directories \"127.0.0.1:NNNN\", and\n\"dumb\") exists within the repository, too.\n\nTo determine this, it first picks the appropriate transport, which is\ndumb HTTP. It then uses the remote\u0027s URL in order to determine whether\nthe repository exists locally on disk. However, the malicious repository\nalso contains an embedded stub repository which is the target of a\nsymbolic link at the local path corresponding to the \"sub\" repository on\ndisk (i.e., there is a symbolic link at \"http:/127.0.0.1/dumb/sub.git\",\npointing to the stub repository via \".git/modules/sub/../../../repo\").\n\nThis stub repository fools Git into thinking that a local repository\nexists at that URL and thus can be cloned locally. The affected call is\nin `get_repo_path()`, which in turn calls `get_repo_path_1()`, which\nlocates a valid repository at that target.\n\nThis then causes Git to set the `is_local` variable to \"1\", and in turn\ninstructs Git to clone the repository using its local clone optimization\nvia the `clone_local()` function.\n\nThe exploit comes into play because the stub repository\u0027s top-level\n\"$GIT_DIR/objects\" directory is a symbolic link which can point to an\narbitrary path on the victim\u0027s machine. `clone_local()` resolves the\ntop-level \"objects\" directory through a `stat(2)` call, meaning that we\nread through the symbolic link and copy or hardlink the directory\ncontents at the destination of the link.\n\nIn other words, we can get steps (1) and (3) to disagree by leveraging\nthe dangling symlink to pick a non-local transport in the first step,\nand then set is_local to \"1\" in the third step when cloning with\n`--separate-git-dir`, which makes the symlink non-dangling.\n\nThis can result in data-exfiltration on the victim\u0027s machine when\nsensitive data is at a known path (e.g., \"/home/$USER/.ssh\").\n\nThe appropriate fix is two-fold:\n\n - Resolve the transport later on (to avoid using the local\n   clone optimization with a non-local transport).\n\n - Avoid reading through the top-level \"objects\" directory when\n   (correctly) using the clone_local() optimization.\n\nThis patch merely demonstrates the issue. The following two patches will\nimplement each part of the above fix, respectively.\n\n[^1]: Provided that any target directory does not contain symbolic\n  links, in which case the changes from 6f054f9fb3 (builtin/clone.c:\n  disallow `--local` clones with symlinks, 2022-07-28) will abort the\n  clone.\n\nReported-by: yvvdwf \u003cyvvdwf@gmail.com\u003e\nSigned-off-by: Taylor Blau \u003cme@ttaylorr.com\u003e\nSigned-off-by: Junio C Hamano \u003cgitster@pobox.com\u003e\n",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "7ebd31a15086c56ef62b0eaf021abff5835215c9",
      "new_mode": 33261,
      "new_path": "t/t5619-clone-local-ambiguous-transport.sh"
    }
  ]
}
