Skip to content

Enforce file permissions#2286

Merged
melekes merged 7 commits intodevelopfrom
file_perms
Sep 17, 2018
Merged

Enforce file permissions#2286
melekes merged 7 commits intodevelopfrom
file_perms

Conversation

@liamsi
Copy link
Contributor

@liamsi liamsi commented Aug 27, 2018

Resolves #2285

@liamsi liamsi changed the base branch from master to develop August 27, 2018 13:54
@codecov-io
Copy link

codecov-io commented Aug 27, 2018

Codecov Report

Merging #2286 into develop will increase coverage by 1.4%.
The diff coverage is 47.05%.

@@            Coverage Diff             @@
##           develop    #2286     +/-   ##
==========================================
+ Coverage    61.26%   62.67%   +1.4%     
==========================================
  Files          197      215     +18     
  Lines        16260    17608   +1348     
==========================================
+ Hits          9962    11035   +1073     
- Misses        5431     5659    +228     
- Partials       867      914     +47
Impacted Files Coverage Δ
libs/db/fsdb.go 66.66% <12.5%> (-3.12%) ⬇️
libs/autofile/autofile.go 75.34% <77.77%> (+5.64%) ⬆️
consensus/replay.go 54.85% <0%> (-11.66%) ⬇️
libs/db/go_level_db.go 65% <0%> (-1.67%) ⬇️
crypto/encoding/amino/amino.go 84.21% <0%> (-1.51%) ⬇️
consensus/state.go 76.58% <0%> (-1.07%) ⬇️
libs/clist/clist.go 65.44% <0%> (-1.06%) ⬇️
node/node.go 64.26% <0%> (-0.76%) ⬇️
state/txindex/kv/kv.go 74.77% <0%> (-0.44%) ⬇️
privval/priv_validator.go 69.44% <0%> (ø) ⬆️
... and 58 more

Copy link
Contributor

@melekes melekes left a comment

Choose a reason for hiding this comment

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

🥇 🏎 🍰

@melekes
Copy link
Contributor

melekes commented Aug 27, 2018

Do you think it make sense to test new behaviour?

@liamsi
Copy link
Contributor Author

liamsi commented Aug 27, 2018

Do you think it make sense to test new behaviour?

I think it basically always makes sense to test any new behaviour. I'm not sure in this case though: The methods in question are private and it would be like testing the correctness of the standard go-library (and if we can properly write to the filesystem where the test is running etc).

But let me add a few lines to the existing autofile_test.go. I would not introduce a new test-file that only has one test (for write) for fsdb.go.

if err != nil {
return err
}
fInf, err := file.Stat()
Copy link
Contributor

Choose a reason for hiding this comment

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

May I suggest a better name: fileInfo? It's a bit hard to decipher fInf.

Copy link
Contributor

Choose a reason for hiding this comment

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

I will change myself if that's ok

libs/db/fsdb.go Outdated
return err
}
defer f.Close()
fInf, err := f.Stat()
Copy link
Contributor

Choose a reason for hiding this comment

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

same here

// Manually modify file permissions, close, and reopen using autofile:
// We expect the file permissions to be changed back to the intended perms.
file, err := ioutil.TempFile("", "permission_test")
if 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.

Would be nice to use https://github.com/stretchr/testify here to simplify code

require.NoError(t, err)

Copy link
Contributor

@ValarDragon ValarDragon left a comment

Choose a reason for hiding this comment

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

This change looks fine to me, but I'd prefer that we don't change the permission mid-session. Most other tools I use don't do this, they just error on invalid perms. (e.g. things that involve ssh keys) This is going to be an edge case that may frustrate users if they want these files to have certain perms, and they get silently changed. If we prefer to auto-upgrade the perms, we should at least log that we are doing so.

This is kind of minor, so I'm fine with the overall change being merged. (Hence the approve)

@melekes
Copy link
Contributor

melekes commented Aug 28, 2018

On the second thought, I don't think we should try to fix errors one level above Tendermint. If someone hacked the OS and changed file's permissions, then owners are screwed in any case. If it's due to some glitch, again it's not the Tendermint task to log that permissions got changed (although it may be nice).

@liamsi
Copy link
Contributor Author

liamsi commented Aug 28, 2018

An alternative would be to error if the file permissions changed (as suggested in the related issue #2285). Could be a sentinel error so the caller can handle it and give the user a proper error message on the command-line / the UI. I do not think we should just ignore it if the permissions changed (either due some glitch or a hack).

@liamsi
Copy link
Contributor Author

liamsi commented Aug 28, 2018

This is kind of minor, so I'm fine with the overall change being merged. (Hence the approve)

@ValarDragon did you request changes by accident then?

@melekes
Copy link
Contributor

melekes commented Aug 28, 2018

if the permissions changed

keep in mind that if Tendermint loses permission to write to that file, it will panic. so we're only talking about group rw/other rw permissions.

Copy link
Contributor

@xla xla left a comment

Choose a reason for hiding this comment

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

Also in favour of returning a meaningful error instead of changing the perms.

@melekes
Copy link
Contributor

melekes commented Sep 4, 2018

keep in mind that if Tendermint loses permission to write to that file, it will panic. so we're only talking about group rw/other rw permissions.

That said, the reasonable thing to do is to log a warning (e.g. "%s permissions were modified (was: %v, become: %v)"). Don't think we should panic if Tendermint still has a right to write to the file.

@melekes melekes changed the title Enforce file permissions [WIP] Enforce file permissions Sep 4, 2018
- if we can't read the file, we'll still panic
err = af.Close()
require.NoError(t, err)
require.Error(t, err)
t.Log(err)
Copy link
Contributor Author

@liamsi liamsi Sep 4, 2018

Choose a reason for hiding this comment

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

Will print:
expected file permissions: -rw-------, got: -rwxr-xr-x: file permissions changed

return err
}
return errors.WithMessage(PermissionsChangedErr,
fmt.Sprintf("expected file permissions: %v, got: %v", autoFilePerms, fileInfo.Mode()))
Copy link
Contributor

Choose a reason for hiding this comment

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

does it make sense to print the filename too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, now it prints:

file: [/var/folders/qf/7nq2274n50v5x9s2y4jcmfgm0000gn/T/permission_test343097720]
		expected file permissions: -rw-------, got: -rwxr-xr-x

autoFilePerms = os.FileMode(0600)
)

var PermissionsChangedErr = errors.New("file permissions changed")
Copy link
Contributor

Choose a reason for hiding this comment

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

godoc is missing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added

"sync"
"time"

"github.com/pkg/errors"
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I started with that but it was annoyingly difficult to sth simple as just annotating an error with additional info (the formatted string). Maybe, I was just using it wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a simple example somewhere?

I want a sentinel error as above PermissionsChangedErr (such that the caller can check against it) and simply annotate it with more info. I can use ErrorWrap but I do not see a way to get the annotated content without the whole stack trace a la:

=== RUN   TestOpenAutoFilePerms
--- PASS: TestOpenAutoFilePerms (0.00s)
	autofile_test.go:85: --= Error =--
		Data: "file permissions changed"
		Msg Traces:
		    0  /Users/ismail/go/src/github.com/tendermint/tendermint/libs/autofile/autofile.go:133 - [/var/folders/qf/7nq2274n50v5x9s2y4jcmfgm0000gn/T/permission_test853068086]: expected file permissions : -rw-------, got: -rwxr-xr-x
		Stack Trace:
		    0  /Users/ismail/go/src/github.com/tendermint/tendermint/libs/common/errors.go:14
		    1  /Users/ismail/go/src/github.com/tendermint/tendermint/libs/autofile/autofile.go:133
		    2  /Users/ismail/go/src/github.com/tendermint/tendermint/libs/autofile/autofile.go:60
		    3  /Users/ismail/go/src/github.com/tendermint/tendermint/libs/autofile/autofile_test.go:82
		    4  /usr/local/Cellar/go/1.10.3/libexec/src/testing/testing.go:777
		    5  /usr/local/Cellar/go/1.10.3/libexec/src/runtime/asm_amd64.s:2362
		--= /Error =--
PASS

That's way to verbose for this simple case. Basically, we just want the first msg trace (as possible with github.com/pkg/errors via errors.WithMessage). cmn.NewErrorWithData doesn't provide sth. similar either. NewError can not keep the orig. error/Error.

Am I missing sth. obvious here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just got rid of github.com/pkg/errors and type aliased a string. I think that is the simplest way to handle this.

@liamsi liamsi changed the title [WIP] Enforce file permissions Enforce file permissions Sep 7, 2018
Copy link
Contributor

@xla xla left a comment

Choose a reason for hiding this comment

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

Some changes to make the code more idiomatic.

)

// PermissionsChangedErr occurs if the file permission have changed since the file was created.
type PermissionsChangedErr string
Copy link
Contributor

Choose a reason for hiding this comment

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

Prefixing of Err is the de facto standard, compared to suffxing: PermissionsChangedErr -> ErrPermissionsChanged.

return err
}
if fileInfo.Mode() != autoFilePerms {
return PermissionsChangedErr(fmt.Sprintf("file: [%v]\nexpected file permissions: %v, got: %v",
Copy link
Contributor

Choose a reason for hiding this comment

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

This error string construction might be better placed in the Error method of the error type and carry the relevant info in a struct:

type ErrPermissionsChanged struct {
	name          string
	expected, got os.FileMode
}

func (e ErrPermissionsChanged) Error() string {
	return fmt.Sprintf(
		"file: [%v]\nexpected file permissions: %v, got: %v",
		e.name,
		e.expected,
		e.got,
	)
}

return err
}
if fileInfo.Mode() != autoFilePerms {
return PermissionsChangedErr(fmt.Sprintf("file: [%v]\nexpected file permissions: %v, got: %v",
Copy link
Contributor

Choose a reason for hiding this comment

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

Additionally this way of formatting, I know brought it up before, is confusing. There is no clear rule to when to break a line and recognising where one construct starts and another requires a lot of effort. More consistently it should look like this:

	return PermissionsChangedErr(
		fmt.Sprintf(
			"file: [%v]\nexpected file permissions: %v, got: %v",
			file.Name(),
			autoFilePerms,
			fileInfo.Mode(),
		),
	)

This is allows for faster reading and faster editing of the code.

libs/db/fsdb.go Outdated
)

// PermissionsChangedErr occurs if the file permission have changed since the file was created.
type PermissionsChangedErr string
Copy link
Contributor

Choose a reason for hiding this comment

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

Prefix over suffix as above.

Is there a reason that both packages need to export their own version of the same error, can those be consolidated?

Copy link
Contributor Author

@liamsi liamsi Sep 14, 2018

Choose a reason for hiding this comment

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

Of course they could. What package would be a good place? libs/common/errror_types.go ?

Copy link
Contributor

Choose a reason for hiding this comment

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

libs/common does have errors, but comes with a lot of other things. I'd say a central errors package would be good, maybe for now under libs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point. done.

- prefix instead of suffix
- add state to err and construct formatting in Error() method
- move error to libs/errors
Copy link
Contributor

@xla xla left a comment

Choose a reason for hiding this comment

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

👍 :octocat: :shipit: 🍡

@melekes melekes merged commit 8ae3334 into develop Sep 17, 2018
@melekes melekes deleted the file_perms branch September 17, 2018 10:38
melekes added a commit that referenced this pull request Oct 9, 2018
The current behavior is panic if autofile#openFile returns an error. But
for ErrPermissionsChanged, we should warn a user that permissions are
  different (given we still retain the ability to write to the file).

This also modifies fsdb.

Issue from our Riot:

```
S: `Panicked on a Sanity Check: Error opening Mempool wal file: file: [/tendermint/mytestnet/node0/data/mempool.wal/wal] expected file permissions: -rw-------, got: -rwxrwxrwx`
M: somebody/something changed wal file permissions
S: I'm running a docker-compose setup with 4 nodes, It used to work with tendermint 22.0 and started to break when upgraded to tendermint 25.0
```

Refs #2286
melekes added a commit that referenced this pull request Oct 9, 2018
The current behavior is panic if autofile#openFile returns an error. But
for ErrPermissionsChanged, we should warn a user that permissions are
  different (given we still retain the ability to write to the file).

This also modifies fsdb.

Issue from our Riot:

```
S: `Panicked on a Sanity Check: Error opening Mempool wal file: file: [/tendermint/mytestnet/node0/data/mempool.wal/wal] expected file permissions: -rw-------, got: -rwxrwxrwx`
M: somebody/something changed wal file permissions
S: I'm running a docker-compose setup with 4 nodes, It used to work with tendermint 22.0 and started to break when upgraded to tendermint 25.0
```

Refs #2286
melekes added a commit that referenced this pull request Nov 5, 2018
current code results in panic and we certainly don't want that.
#2286 (comment)
melekes added a commit that referenced this pull request Nov 5, 2018
current code results in panic and we certainly don't want that.
#2286 (comment)
enlight pushed a commit to enlight/tendermint that referenced this pull request Nov 6, 2018
current code results in panic and we certainly don't want that.
tendermint#2286 (comment)
ebuchman pushed a commit that referenced this pull request Nov 16, 2018
current code results in panic and we certainly don't want that.
#2286 (comment)
kfangw pushed a commit to kfangw/blockchain that referenced this pull request Jun 10, 2019
current code results in panic and we certainly don't want that.
tendermint/tendermint#2286 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants