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 race in local storage #14888

Merged
merged 4 commits into from
Mar 5, 2021
Merged

Conversation

zeripath
Copy link
Contributor

@zeripath zeripath commented Mar 4, 2021

LocalStorage should only put completed files in position

Signed-off-by: Andrew Thornton art27@cantab.net

LocalStorage should only put completed files in position

Signed-off-by: Andrew Thornton <art27@cantab.net>
@zeripath zeripath added this to the 1.14.0 milestone Mar 4, 2021
@zeripath
Copy link
Contributor Author

zeripath commented Mar 4, 2021

There are a couple of other races in here - which I don't really know how to fix.

The issues are:

  • A broken upload will temporarily appear in the store before being taken out but could be downloaded in the intervening period - and you could actually delete a good upload whilst deleting a bad one.
  • A broken object in the store being noticed at download time isn't very easy to fix either.

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Mar 4, 2021
@zeripath
Copy link
Contributor Author

zeripath commented Mar 4, 2021

This PR however does get rid of the most egregious problem.

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Mar 4, 2021
modules/storage/local.go Outdated Show resolved Hide resolved
@@ -46,9 +49,14 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
return nil, err
}

if config.TemporaryPath == "" {
Copy link
Member

Choose a reason for hiding this comment

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

Put them to a system temp directory is better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These files may be large and the system temporary directory is not guaranteed to be able to cope.

The system tempdir may be on a different volume in Windows or may be on a different filesystem.

The only place we know for sure that LFS files will fit and should be renamed atomically is if they're in the LFS repository path.

The temporary directory is configurable - although I've not explicitly documented it here: set TEMPORARY_PATH for the storage

@zeripath
Copy link
Contributor Author

zeripath commented Mar 5, 2021

Fundamentally the other races exist because there is a verification step that the storage system is not aware of and isn't doing.

But thinking on I suppose we could "buffer" the data being passed to the storage system so that by the time eof is called we know that the data we're passing has actually got the right SHA256 and is the right size.

That is: instead of using a teereader we wrap the reader and write to the hash and keep account of the size during the Read(...)

Then when EOF is returned from the body reader we check the hash and the size - determine if it's correct before returning io.EOF otherwise we return some other error.

The other error will then percolate up to the storage reader and its io.copy killing them and aborting the storage. Boom.

Verification in stream and no more races.

@zeripath
Copy link
Contributor Author

zeripath commented Mar 5, 2021

Now it's likely that the body reader implements io.WriterTo which may mean we need to implement io.Writer in addition to WriterTo to do the same trick just slightly differently.

@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Mar 5, 2021
@6543 6543 merged commit 144cfe5 into go-gitea:master Mar 5, 2021
@zeripath zeripath deleted the fix-lfs-contentstore-races branch March 5, 2021 16:20
6543 pushed a commit to 6543-forks/gitea that referenced this pull request Mar 6, 2021
LocalStorage should only put completed files in position

Signed-off-by: Andrew Thornton <art27@cantab.net>
@6543 6543 added the backport/done All backports for this PR have been created label Mar 6, 2021
@6543
Copy link
Member

6543 commented Mar 6, 2021

Backport -> #14901

6543 added a commit that referenced this pull request Mar 6, 2021
LocalStorage should only put completed files in position

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
@zeripath
Copy link
Contributor Author

zeripath commented Mar 6, 2021

Sorry was in bed so couldn't do the backport!

zeripath added a commit that referenced this pull request Mar 6, 2021
Continuing on from #14888

The previous implementation has race whereby an incomplete upload or
hash mismatch upload can end up in the ContentStore. This PR moves the
validation into the reader so that if there is a hash error or size
mismatch the reader will return with an error instead of an io.EOF
causing the storage to abort the storage.

Signed-off-by: Andrew Thornton <art27@cantab.net>
zeripath added a commit to zeripath/gitea that referenced this pull request Mar 6, 2021
Backport go-gitea#14895

Continuing on from go-gitea#14888

The previous implementation has race whereby an incomplete upload or
hash mismatch upload can end up in the ContentStore. This PR moves the
validation into the reader so that if there is a hash error or size
mismatch the reader will return with an error instead of an io.EOF
causing the storage to abort the storage.

Signed-off-by: Andrew Thornton <art27@cantab.net>
lafriks pushed a commit that referenced this pull request Mar 6, 2021
Backport #14895

Continuing on from #14888

The previous implementation has race whereby an incomplete upload or
hash mismatch upload can end up in the ContentStore. This PR moves the
validation into the reader so that if there is a hash error or size
mismatch the reader will return with an error instead of an io.EOF
causing the storage to abort the storage.

Signed-off-by: Andrew Thornton <art27@cantab.net>
@go-gitea go-gitea locked and limited conversation to collaborators May 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
backport/done All backports for this PR have been created lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. type/bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants