git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 1/2] worktree: don't read out of bounds

From
Junio C Hamano <gitster@pobox.com>
Date
Jul 25, 2026, 16:51 UTC
Message-ID
<xmqqbjbvypv3.fsf@gitster.g>
In-Reply-To
<8bc69c6b80ed42888327331b1567cecf7225ea7e.1784978348.git.gitgitgadget@gmail.com>
"Matthias Aßhauer via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 5 quoted lines
> `worktree_basename` tries to read from memory before the passed `path`
> string, if `path` is empty (or only consists of directory separators).
> That results in unexpected nonsense data being returned to the caller,
> which can lead to issues, such as `git worktree add ""` recursively
> deleting the current working directory, including `.git`.

OK, so you do want to handle a case where path is something silly like "///".

Show 5 quoted lines
> Stop reading out of bounds in these cases to avoid that behaviour.
>
> This leads to `git worktree add ""` consistently exiting with the
> message `BUG: How come '' becomes empty after sanitization?`, which is
> still undesirable, but at least it doesn't result in data loss anymore.
OK.
Show 15 quoted lines
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 4bc7b4f6e7..d8188035db 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -297,17 +297,21 @@ static void remove_junk_on_signal(int signo)
>  static const char *worktree_basename(const char *path, int *olen)
>  {
>  	const char *name;
> -	int len;
> +	int len, len2;
>  
> -	len = strlen(path);
> +	len2 = len = strlen(path);
>  	while (len && is_dir_sep(path[len - 1]))
>  		len--;

These two 'len' variables should have clear names to distinguish what each length represents. Rather than introducing a cryptic 'len2', give it a more meaningful name, and rename 'len' as well if necessary.

I suspect that it is to remember the original length of the 'path' before stripping the trailing directory separators?

Show 5 quoted lines
> -	for (name = path + len - 1; name > path; name--)
> -		if (is_dir_sep(*name)) {
> -			name++;
> -			break;
> -		}

When 'len' is 0, the original code sets 'name' to '&path[-1]' and does not enter the loop. However, '*olen' is set to 0, and 'name', pointing before the start of the string, is returned. If left unfixed, callers pass it to xstrndup(), strbuf_add(), and the like, reading memory before the start of the string, which is horrible and worth fixing.

Show 9 quoted lines
> +	if(len) {
> +		for (name = path + len - 1; name > path; name--)
> +			if (is_dir_sep(*name)) {
> +				name++;
> +				break;
> +			}
> +	}
> +	else
> +		name = path + len2;
Style:
 (1) Missing SP between 'if' and '(len'.
 (2) 'else' sits on the same line as '}' that closes the 'if'
     clause.
 (3) When any one branch of an 'if'...'else if'...'else' cascade
     needs a pair of braces to group multiple statements, all other
     branches must use braces as well.
Taken together:
	if (len) {
		...
	} else {
		...
	}

As for what the patch intends to do, setting 'name = path + len2' when 'len' is 0 breaks when 'path' consists only of directory separators (for example, "/" or "///"), no?

In that case, 'len2' is positive (for example, 3) while 'len' is 0. In add_worktree(), 'path + len - name' evaluates to (path + 0) - (path + 3) = -3. Passed as size_t to strbuf_add(), this wraps around to SIZE_MAX - 2 (approx. 18 exabytes), leading to a buffer allocation failure or a crash.

Rather than calculating 'path - 1' out of bounds or introducing 'len2', worktree_basename() can simply keep 'name = path' when 'len' is 0. Using an integer index loop 'for (int i = len - 1; 0 <= i; i--)' avoids pointer arithmetic before the start of the buffer entirely, I would think. Or am I missing something?

Thanks.
Previous: Matthias Aßhauer via GitGitGadgetNext: René Scharfe
Message 3 of 11 in “worktree: Fix out of bounds read that causes data loss and reject invalid empty input in worktree add”
  1. 0/2 worktree: Fix out of bounds read that causes data loss and reject invalid empty input in worktree addMatthias Aßhauer via GitGitGadget, Jul 25, 2026
  2. 1/2 worktree: don't read out of boundsMatthias Aßhauer via GitGitGadget, Jul 25, 2026
  3. Junio C HamanoJul 25, 2026
  4. René ScharfeJul 31, 2026
  5. 2/2 worktree: reject empty stringMatthias Aßhauer via GitGitGadget, Jul 25, 2026
  6. René ScharfeAug 2, 2026
  7. René ScharfeAug 2, 2026
  8. worktree: Fix out of bounds read that causes data loss and reject invalid empty input in worktree addRené Scharfe, Aug 11, 2026
  9. Junio C HamanoAug 11, 2026
  10. René ScharfeAug 16, 2026
  11. Junio C HamanoAug 16, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.