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

lib/model: Allow updates to deleted files (fixes #3839) #3840

Conversation

AudriusButkevicius
Copy link
Member

To be honest, I still think this somewhat contains holes.
This whole "resurrecting dir" stuff is now impossible.

@calmh
Copy link
Member

calmh commented Dec 24, 2016

I see this but I have to think more carefully about it than I'm capable of tonight.

// and not a symlink or empty space. If it's already deleted, handle
// the check inside deleteFile deleteDir only in the scenario where
// the subject we are supposed to delete actually exists.
if !fi.IsDeleted() && !osutil.IsDir(f.dir, filepath.Dir(fi.Name)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems dangerous, because a path that traverses Symlinks might end up in buckets. I think this allows an attacker to delete known files outside of the folder.

// and not a symlink or empty space. If it's already deleted, handle
// the check inside deleteFile deleteDir only in the scenario where
// the subject we are supposed to delete actually exists.
if !fi.IsDeleted() && !osutil.IsDir(f.dir, filepath.Dir(fi.Name)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This change is unnecessary. (Line 515)

// Verify that the thing we are handling lives inside a directory,
// and not a symlink or empty space.
if !osutil.IsDir(f.dir, filepath.Dir(file.Name)) {
f.newError(file.Name, "deleteDir isDir", errNotDir)
Copy link
Contributor

@Unrud Unrud Dec 26, 2016

Choose a reason for hiding this comment

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

The delete was successful at this point, the error is pointless.
E.g. foo/bar was renamed to baz/bar and a Symlink foo -> baz was created. The Lstat check succeeds but the real file foo/bar doesn't exist anymore.

I think that the following check should be enough:

if !osutil.IsDir(f.dir, filepath.Dir(file.Name)) {
    f.dbUpdates <- dbUpdateJob{file, dbUpdateDeleteDir}
    return
}

Lstat is not required.

// Verify that the thing we are handling lives inside a directory,
// and not a symlink or empty space.
if !osutil.IsDir(f.dir, filepath.Dir(file.Name)) {
f.newError(file.Name, "deleteFile isDir", errNotDir)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as deleteDir

@@ -1532,7 +1540,7 @@ func (f *sendReceiveFolder) dbUpdaterRoutine() {
}
lastFile = file
if err := syncFn(file); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

The above changes allow file to traverse a Symlink. You have to check with isDir, before calling syncFn. It prevents fsyncing files outside of the folder and the fsync errors disappear.

Unrud pushed a commit to Unrud/syncthing that referenced this pull request Dec 27, 2016
@calmh
Copy link
Member

calmh commented Dec 29, 2016

Instead of handling the inconsistency on the filesystem, could we fix it in the database directly?

@AudriusButkevicius
Copy link
Member Author

Not sure what you mean. Wasn't the point thatthe db is racey compared with the fs?

@calmh
Copy link
Member

calmh commented Dec 30, 2016

Maybe I'm misunderstanding. But isn't the problem that we have:

  • dir
    • dir/file

and we get deletes for them:

  • dir (deleted)
    • dir/file (deleted)

so we remove both. We then get an update:

  • dir/file (updated)

but we can't resurrect it because the dir is gone and fails the parent check? Similar thing when dir is ignored and dir/file unignored.

My alternative idea for handling this is in WithNeed, where it would be able to track that it's descended into the deleted dir and emit a need for that when it emits the need for dir/file. Let me try and write that up and see if it fixes the issue.

@AudriusButkevicius
Copy link
Member Author

AudriusButkevicius commented Dec 30, 2016

I don't think thats the problem as we'd get the dir entry too.

The issue as far as I understand it is:

A and B has dir/file
A deletes dir and dir/file
B deletes it too
B goes offline
A recreates dir and dir/file (version bump)
A deletes dir and dir/file (version bump)
B comes online
B can never accept the new index entries for stuff that does not exist.

@AudriusButkevicius AudriusButkevicius deleted the delete-the-delete branch January 15, 2017 12:35
Unrud pushed a commit to Unrud/syncthing that referenced this pull request Jan 19, 2017
@st-review st-review added the frozen-due-to-age Issues closed and untouched for a long time, together with being locked for discussion label Jan 16, 2018
@syncthing syncthing locked and limited conversation to collaborators Jan 16, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
frozen-due-to-age Issues closed and untouched for a long time, together with being locked for discussion
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants