Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix memory corruption with FSMonitor-enabled unpack_trees() #891

Conversation

dscho
Copy link
Member

@dscho dscho commented Mar 2, 2021

While dog-fooding Jeff Hostetler's FSMonitor patches, I ran into a really obscure segmentation fault during one of my epic Git for Windows rebases. Turns out that this bug is quite old.

cc: Derrick Stolee stolee@gmail.com

In 56c6910 (fsmonitor: change last update timestamp on the
index_state to opaque token, 2020-01-07), we forgot to adjust the part
of `unpack_trees()` that copies the FSMonitor "last-update" information
that we copy from the source index to the result index since 679f2f9
(unpack-trees: skip stat on fsmonitor-valid files, 2019-11-20).

Since the "last-update" information is no longer a 64-bit number, but a
free-form string that has been allocated, we need to duplicate it rather
than just copying it.

This is important because there _are_ cases when `unpack_trees()` will
perform a oneway merge that implicitly calls `refresh_fsmonitor()`
(which will allocate that "last-update" token). This happens _after_
that token was copied into the result index. However, we _then_ call
`check_updates()` on that index, which will _also_ call
`refresh_fsmonitor()`, accessing the "last-update" string, which by now
would be released already.

In the instance that lead to this patch, this caused a segmentation
fault during a lengthy, complicated rebase involving the todo command
`reset` that (crucially) had to updated many files. Unfortunately, it
seems very hard to trigger that crash, therefore this patch is not
accompanied by a regression test.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In 56c6910 (fsmonitor: change last update timestamp on the
index_state to opaque token, 2020-01-07), we forgot to adjust
`discard_index()` to release the "last-update" token: it is no longer a
64-bit number, but a free-form string that has been allocated.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho
Copy link
Member Author

dscho commented Mar 17, 2021

/submit

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 17, 2021

Submitted as pull.891.git.1615995049.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git pr-891/dscho/fix-fsmonitor-crash-v1

To fetch this version to local tag pr-891/dscho/fix-fsmonitor-crash-v1:

git fetch --no-tags https://github.com/gitgitgadget/git tag pr-891/dscho/fix-fsmonitor-crash-v1

@@ -1544,8 +1544,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
o->merge_size = len;
Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> --- a/unpack-trees.c
> +++ b/unpack-trees.c
> @@ -1544,8 +1544,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
>  	o->merge_size = len;
>  	mark_all_ce_unused(o->src_index);
>  
> -	if (o->src_index->fsmonitor_last_update)
> -		o->result.fsmonitor_last_update = o->src_index->fsmonitor_last_update;
> +	o->result.fsmonitor_last_update =
> +		xstrdup_or_null(o->src_index->fsmonitor_last_update);

And this won't happen twice, so there is no need to free what is in
the o->result side before assignment.  And 2/2 frees it so we do not
leak at the end either.

Will queue; thanks.

>  
>  	/*
>  	 * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 17, 2021

On the Git mailing list, Derrick Stolee wrote (reply to this):

On 3/17/2021 11:30 AM, Johannes Schindelin via GitGitGadget wrote:
> While dog-fooding Jeff Hostetler's FSMonitor patches, I ran into a really
> obscure segmentation fault during one of my epic Git for Windows rebases.

Thanks for dogfooding!

> Turns out that this bug is quite old.

A little over a year, yes, since the v2 hook was committed. It's old
enough that these could be applied to 'maint'.
 
> Johannes Schindelin (2):
>   fsmonitor: fix memory corruption in some corner cases
>   fsmonitor: do not forget to release the token in `discard_index()`

The patches themselves are correct and describe the problem well.
They only show up during non-trivial uses of FS Monitor and index
updates, so I understand your hesitance to write tests that trigger
these problems.

Thanks,
-Stolee

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 17, 2021

User Derrick Stolee <stolee@gmail.com> has been added to the cc: list.

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 17, 2021

This branch is now known as js/fsmonitor-unpack-fix.

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 17, 2021

This patch series was integrated into seen via git@5f24c7e.

@gitgitgadget gitgitgadget bot added the seen label Mar 17, 2021
@gitgitgadget
Copy link

gitgitgadget bot commented Mar 17, 2021

There was a status update about the branch js/fsmonitor-unpack-fix on the Git mailing list:

The data structure used by fsmonitor interface was not properly
duplicated during an in-core merge, leading to use-after-free etc.

Will merge to 'next'.

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 19, 2021

This patch series was integrated into seen via git@10078f7.

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 19, 2021

This patch series was integrated into next via git@2ab614f.

@gitgitgadget gitgitgadget bot added the next label Mar 19, 2021
@gitgitgadget
Copy link

gitgitgadget bot commented Mar 19, 2021

On the Git mailing list, Johannes Schindelin wrote (reply to this):

Hi Stolee,

On Wed, 17 Mar 2021, Derrick Stolee wrote:

> On 3/17/2021 11:30 AM, Johannes Schindelin via GitGitGadget wrote:
> > While dog-fooding Jeff Hostetler's FSMonitor patches, I ran into a really
> > obscure segmentation fault during one of my epic Git for Windows rebases.
>
> Thanks for dogfooding!

I'm completely selfish here, as I want to benefit from the speed myself,
and that's also the reason why I added this as an experimental option to
Git for Windows v2.31.0: That way, I can test it everywhere (and so can
others).

> > Turns out that this bug is quite old.
>
> A little over a year, yes, since the v2 hook was committed. It's old
> enough that these could be applied to 'maint'.

Indeed. Even better: if you look closely at the GitGitGadget PR, you will
see that I based it on `kw/fsmonitor-watchman-racefix`.

> > Johannes Schindelin (2):
> >   fsmonitor: fix memory corruption in some corner cases
> >   fsmonitor: do not forget to release the token in `discard_index()`
>
> The patches themselves are correct and describe the problem well.
> They only show up during non-trivial uses of FS Monitor and index
> updates, so I understand your hesitance to write tests that trigger
> these problems.

Right. For me, I ran into them only in one specific instance, when
rebasing Git for Windows' patch thicket onto `seen`, and then only when
merging a topic branch with a rather big diff.

Thanks,
Dscho

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 19, 2021

This patch series was integrated into seen via git@1dd4e74.

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 19, 2021

This patch series was integrated into next via git@1dd4e74.

@gitgitgadget
Copy link

gitgitgadget bot commented Mar 19, 2021

This patch series was integrated into master via git@1dd4e74.

@gitgitgadget gitgitgadget bot added the master label Mar 19, 2021
@gitgitgadget gitgitgadget bot closed this Mar 19, 2021
@gitgitgadget
Copy link

gitgitgadget bot commented Mar 19, 2021

Closed via 1dd4e74.

@dscho dscho deleted the fix-fsmonitor-crash branch March 21, 2021 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant