Commit Graph

482 Commits

Author SHA1 Message Date
Jakob Unterwurzacher de3a2c1895 fusefrontend: mark a few more functions as symlink-safe / unsafe 2019-01-01 16:24:25 +01:00
Jakob Unterwurzacher 8586a83825 fusefrontend: use openBackingDir in ctlsock interface
Instead of calling syscall.Open() ourselves, rely on
openBackingDir().
2019-01-01 16:24:20 +01:00
Jakob Unterwurzacher 0c1ceed1fa fusefrontend: make GetAttr() symlink-safe
Use openBackingDir() and Fstatat().

High performance impact, though part of it should be
mitigated by adding DirIV caching to the new code paths.

$ ./benchmark.bash
Testing gocryptfs at /tmp/benchmark.bash.Eou: gocryptfs v1.6-37-ge3914b3-dirty; go-fuse v20170619-66-g6df8ddc; 2018-10-14 go1.11
WRITE: 262144000 bytes (262 MB, 250 MiB) copied, 1.2289 s, 213 MB/s
READ:  262144000 bytes (262 MB, 250 MiB) copied, 1.02616 s, 255 MB/s
UNTAR: 24.490
MD5:   13.120
LS:    3.368
RM:    9.232
2019-01-01 16:24:09 +01:00
Jakob Unterwurzacher 932efbd459 fusefrontend: make openBackingDir() symlink-safe
openBackingDir() used encryptPath(), which is not symlink-safe
itself. Drop encryptPath() and implement our own directory walk.

Adds three seconds to untar and two seconds to rm:

$ ./benchmark.bash
Testing gocryptfs at /tmp/benchmark.bash.MzG: gocryptfs v1.6-36-g8fb3c2f-dirty; go-fuse v20170619-66-g6df8ddc; 2018-10-14 go1.11
WRITE: 262144000 bytes (262 MB, 250 MiB) copied, 1.25078 s, 210 MB/s
READ:  262144000 bytes (262 MB, 250 MiB) copied, 1.0318 s, 254 MB/s
UNTAR: 20.941
MD5:   11.568
LS:    1.638
RM:    5.337
2019-01-01 16:24:09 +01:00
Jakob Unterwurzacher 0e2e7c13cf fusefrontend: mark symlink-safe FUSE calls
Document which FUSE calls are already symlink-safe in
the function comment.
2019-01-01 16:24:09 +01:00
Jakob Unterwurzacher c09bf1f228 fusefrontend: make DecryptPath() symlink-safe
DecryptPath is now symlink-safe through the use of *at()
functions.
2019-01-01 16:24:09 +01:00
Jakob Unterwurzacher ed6ed513d7 fusefrontend: make Access() symlink-safe.
Make Access() symlink-safe through use of faccessat.
2019-01-01 16:24:09 +01:00
Jakob Unterwurzacher 545a03da24 nametransform: comments: directly link to ioutil.WriteFile fix
So the reader does not have to read through the whole ticket.
The commit message has a nice summary of the problem.
2019-01-01 16:23:28 +01:00
Sebastian Lackner 5713154468 fusefrontend: Fix debug message in doWrite() method. 2019-01-01 16:12:42 +01:00
Sebastian Lackner 9ed60678e5 fusefrontend: Fix order of arguments in debug message for Read() FUSE call. 2019-01-01 16:12:05 +01:00
Sebastian Lackner 87ced5f95d nametransform: Delete incomplete longname files on error. 2019-01-01 16:09:57 +01:00
Sebastian Lackner 24594d99bf configfile: Fix a copy&paste error in validateParams method. 2018-12-28 09:58:46 +01:00
Sebastian Lackner 07c486603c configfile: Explicitly wipe scrypt derived key after decrypting/encrypting master key.
Further raises the bar for recovering keys from memory.
2018-12-27 18:47:14 +01:00
Sebastian Lackner 874eaf9734 Assorted spelling fixes.
Mostly detected with the 'codespell' utility, but also includes some
manual grammar fixes.
2018-12-27 15:19:55 +01:00
Sebastian Lackner 4c2ff26457 fusefrontend: Remove unnecessary check in doRead function.
The same condition is already checked a few lines above, and 'err' is not
changed inbetween.
2018-12-27 15:18:03 +01:00
Sebastian Lackner 1ced0b192e fusefrontend: Don't treat Fchownat error as failure in Mkdir.
The directory was already created, so return success even if Fchownat fails.
The same error handling is already used if fs.args.PlaintextNames is false.
2018-12-27 15:16:00 +01:00
Sebastian Lackner 5918884926 fusefrontend: Check the correct 'err' variable. 2018-12-27 15:11:23 +01:00
Jakob Unterwurzacher a55e53c196 tests: fix TestPassfileNewline
Due to a copy-paste error, we ran the wrong test in the
subprocess.

Thanks @slackner for noticing at
295d432175 (r31690478) !
2018-12-16 12:33:25 +01:00
Jakob Unterwurzacher 295d432175 passfile: directly read file instead of invoking cat
Allows better error handling, gets rid of the call to an
external program, and fixes https://github.com/rfjakob/gocryptfs/issues/278 .
2018-12-15 17:09:38 +01:00
Jakob Unterwurzacher e665df7179 syscallcompat: downgrade DT_UNKNOWN message level on XFS
Old XFS filesystems always return DT_UNKNOWN. Downgrade the message
to "info" level if we are on XFS.

Using the "warning" level means that users on old XFS filesystems
cannot run the test suite as it intentionally aborts on any
warnings.

Fixes https://github.com/rfjakob/gocryptfs/issues/267
2018-11-17 17:44:21 +01:00
Jakob Unterwurzacher 1ed08c7384 tlog: disable color codes when switching to syslog
When gocryptfs was started on a terminal and later
daemonized, the color codes stayed active in the syslog
output.

The codes are not visible in "journalctl -f", which is why
I have not noticed it yet, but they do show up in normal
syslog as the usual "#033[33m" crap.
2018-10-17 22:34:30 +02:00
Jakob Unterwurzacher 4cdf6b9af9 fusefronted: log more details on WriteAt failures
Also log inode number, fd number, offset and length.

Maybe help debugging https://github.com/rfjakob/gocryptfs/issues/269 .
2018-10-17 22:18:07 +02:00
Jesse Dunietz 87d3ed9187 Add option for autounmount
Even though filesystem notifications aren't implemented for FUSE, I decided to
try my hand at implementing the autounmount feature (#128). I based it on the
EncFS autounmount code, which records filesystem accesses and checks every X
seconds whether it's idled long enough to unmount.

I've tested the feature locally, but I haven't added any tests for this flag.
I also haven't worked with Go before. So please let me know if there's
anything that should be done differently.

One particular concern: I worked from the assumption that the open files table
is unique per-filesystem. If that's not true, I'll need to add an open file
count and associated lock to the Filesystem type instead.

https://github.com/rfjakob/gocryptfs/pull/265
2018-10-11 20:16:45 +02:00
Jakob Unterwurzacher 57a5a8791f tests: syscallcompat: allow failure for symlinks > 1000
MacOS and old XFS versions do not support very long symlinks,
but let's not make the tests fail because of that.

https://github.com/rfjakob/gocryptfs/issues/267
2018-10-11 19:45:47 +02:00
Jakob Unterwurzacher e4f1a32a9a fusefrontend: Fix uint16 build failure on Darwin
Error was:

  # github.com/rfjakob/gocryptfs/internal/fusefrontend
  internal/fusefrontend/fs.go:179: cannot use perms | 256 (type uint16) as type uint32 in argument to syscall.Fchmod
  internal/fusefrontend/fs.go:185: cannot use perms (type uint16) as type uint32 in argument to syscall.Fchmod
2018-09-23 12:17:59 +02:00
Jakob Unterwurzacher a1fb456618 fusefrontend: make Rename() symlink-safe
Use Openat() and the openBackingDir() helper so we
never follow symlinks.
2018-09-23 12:17:59 +02:00
Jakob Unterwurzacher 897bb8924f fusefrontend: make Create() symlink-safe
Use Openat() and the openBackingDir() helper so we
never follow symlinks.
2018-09-23 12:17:59 +02:00
Jakob Unterwurzacher 63762b33af fusefrontend: Open(): fix dirfd leak
Close was missing.
2018-09-23 12:17:59 +02:00
Jakob Unterwurzacher bead82c9fb fusefrontend: add named parameters to openBackingDir
Named parameters make using the function easier.
2018-09-23 12:17:59 +02:00
Jakob Unterwurzacher c270b21efc fusefrontend: get rid of os.File* wrapping
Directly use int file descriptors for the dirfd
and get rid of one level of indirection.
2018-09-23 12:17:26 +02:00
Jakob Unterwurzacher 22fba4ac3e fusefrontent: make Open() symlink-safe 2018-09-23 12:17:26 +02:00
Jakob Unterwurzacher 2d01d5f2d4 tlog: always trim trailing newlines
The messages we print through tlog sometimes do, sometimes do
not contain a trailing newline. The stdlib logger usually drops
trailing newlines automatically, but tlog postfixes ColorReset to
the caller's message, so the logger logic does not work when we
print colored output.

Drop the newlines on our own, and add a test.

Fixes the blank lines in fsck output:

~/go/src/github.com/rfjakob/gocryptfs/tests/fsck$ ./run_fsck.bash
Reading password from extpass program
Decrypting master key
OpenDir "": invalid entry "invalid_file_name.3": illegal base64 data at input byte 17
OpenDir "": invalid entry "invalid_file_name_2": bad message
fsck: corrupt entry in dir "": "invalid_file_name.3"
fsck: corrupt entry in dir "": "invalid_file_name_2"
OpenDir "": invalid entry "invalid_file_name____1": bad message
fsck: corrupt entry in dir "": "invalid_file_name____1"
doRead 4327225: corrupt block #0: stupidgcm: message authentication failed
fsck: error reading file "corrupt_file" (inum 4327225): 5=input/output error
cipherSize 40 < overhead 50: corrupt file

doRead 4327074: corrupt header: ParseHeader: invalid version, want=2 have=22616
cipherSize 40 < overhead 50: corrupt file

fsck: error reading file "corrupt_file_2" (inum 4327074): 5=input/output error
Readlink "s-P7PcQDUcVkoeMDnC3EYA": decrypting target failed: stupidgcm: message authentication failed
fsck: error reading symlink "corrupt_symlink": 5=input/output error
Readlink "iI0MtUdzELPeOAZYwYZFee169hpGgd3l2PXQBcc9sl4": decrypting target failed: illegal base64 data at input byte 0
fsck: error reading symlink "corrupt_symlink_2": 5=input/output error
OpenDir "yrwcjj2qoC4IYvhw9sbfRg": could not read gocryptfs.diriv: wanted 16 bytes, got 17
fsck: error opening dir "diriv_too_long": 5=input/output error
OpenDir "trqecbMNXdzLqzpk7fSfKw": could not read gocryptfs.diriv: wanted 16 bytes, got 3
fsck: error opening dir "diriv_too_short": 5=input/output error
cipherSize 8 < header size 18: corrupt file

readFileID 4327049: incomplete file, got 8 instead of 19 bytes
fsck: corrupt file "incomplete_file_1" (inode 4327049)
readFileID 4327038: incomplete file, got 18 instead of 19 bytes
fsck: corrupt file "incomplete_file_2" (inode 4327038)
cipherSize 1 < header size 18: corrupt file

readFileID 4327063: incomplete file, got 1 instead of 19 bytes
fsck: corrupt file "incomplete_file_3" (inode 4327063)
fsck: error opening dir "missing_diriv": 2=no such file or directory
ListXAttr: invalid xattr name "user.gocryptfs.0a5e7yWl0SGUGeWB0Sy2K0": bad message
fsck: corrupt xattr name on file "xattr_corrupt_name": "user.gocryptfs.0a5e7yWl0SGUGeWB0Sy2K0"
GetXAttr: stupidgcm: message authentication failed
fsck: error reading xattr "user.foo" from "xattr_corrupt_value": 5=input/output error
fsck summary: 15 corrupt files
2018-09-23 11:28:49 +02:00
Jakob Unterwurzacher 737a2f2012 syscallcompat: untangle Openat flag check
Check for O_NWFOLLOW and O_EXCL separately to
make the logic clearer.
2018-09-22 19:38:47 +02:00
Jakob Unterwurzacher e8d8ae54d3 fusefrontend: use OpenDirNofollow in openBackingDir
Rename openBackingPath to openBackingDir and use OpenDirNofollow
to be safe against symlink races. Note that openBackingDir is
not used in several important code paths like Create().

But it is used in Unlink, and the performance impact in the RM benchmark
to be acceptable:

Before

	$ ./benchmark.bash
	Testing gocryptfs at /tmp/benchmark.bash.bYO: gocryptfs v1.6-12-g930c37e-dirty; go-fuse v20170619-49-gb11e293; 2018-09-08 go1.10.3
	WRITE: 262144000 bytes (262 MB, 250 MiB) copied, 1.07979 s, 243 MB/s
	READ:  262144000 bytes (262 MB, 250 MiB) copied, 0.882413 s, 297 MB/s
	UNTAR: 16.703
	MD5:   7.606
	LS:    1.349
	RM:    3.237

After

	$ ./benchmark.bash
	Testing gocryptfs at /tmp/benchmark.bash.jK3: gocryptfs v1.6-13-g84d6faf-dirty; go-fuse v20170619-49-gb11e293; 2018-09-08 go1.10.3
	WRITE: 262144000 bytes (262 MB, 250 MiB) copied, 1.06261 s, 247 MB/s
	READ:  262144000 bytes (262 MB, 250 MiB) copied, 0.947228 s, 277 MB/s
	UNTAR: 17.197
	MD5:   7.540
	LS:    1.364
	RM:    3.410
2018-09-08 19:27:33 +02:00
Jakob Unterwurzacher 930c37e03d syscallcompat: use O_PATH in OpenDirNofollow
This fixes the "0100 directory" problem in reverse mode,
and should be slightly faster.
2018-09-08 18:06:33 +02:00
Jakob Unterwurzacher 9ec9d0c49c syscallcompat: untangle OpenNofollow and rename to OpenDirNofollow
The function used to do two things:

1) Walk the directory tree in a manner safe from symlink attacks
2) Open the final component in the mode requested by the caller

This change drops (2), which was only used once, and lets the caller
handle it. This simplifies the function and makes it fit for reuse in
forward mode in openBackingPath(), and for using O_PATH on Linux.
2018-09-08 17:41:17 +02:00
Jakob Unterwurzacher 2bdf7d5172 configfile: add LoadAndDecrypt wrapper
Callers that do not want to decrypt the masterkey should
call plain Load().

https://github.com/rfjakob/gocryptfs/issues/258
2018-09-08 12:40:29 +02:00
Jakob Unterwurzacher 09d28c293e configfile: split off masterkey decryption
Preparation for fixing https://github.com/rfjakob/gocryptfs/issues/258
2018-09-08 12:19:19 +02:00
Jakob Unterwurzacher 21eaa8f164 configfile: return specific error on empty input
Report the actual problem instead of a generic
"unexpected end of JSON input".

https://github.com/rfjakob/gocryptfs/issues/258
2018-09-08 12:18:26 +02:00
Jakob Unterwurzacher 658cc4aebb syscallcompat: drop Fchmodat flags
These were silently ignored until now (!) but
are rejected by Go 1.11 stdlib.

Drop the flags so the tests work again, until
we figure out a better solution.

https://github.com/golang/go/issues/20130
2018-08-26 13:04:01 +02:00
Jakob Unterwurzacher bd054e70ef trezor: show support in version string
Show enable_trezor in the version string if we were compiled
with `-tags enable_trezor`. And hide the `-trezor` flag from
the help output if we were not.
2018-08-15 23:31:37 +02:00
Jakob Unterwurzacher dbd400d930 fusefrontend: truncateGrowFile: pass zeroPad error to caller
Errors from zeroPad were ignored until now, as discovered
using xfstests generic/083.
2018-08-15 17:25:22 +02:00
Jakob Unterwurzacher 7a02f71fc2 fusefrontend_reverse: reject excludes for the root directory ""
This is most likely a mistake by the user. Reject it.
2018-08-15 12:28:29 +02:00
Jakob Unterwurzacher ec2fdc19cf reverse mode: add --exclude option
https://github.com/rfjakob/gocryptfs/issues/235
2018-08-11 23:26:49 +02:00
Jakob Unterwurzacher f4a972ddf1 configfile: drop superflous Printf
Before:

  $ gocryptfs -fsck .
  LoadConfFile: ReadFile: &os.PathError{Op:"open", Path:"/var/tmp/check-gocryptfs/scratchdev/gocryptfs.conf", Err:0xd}
  Cannot open config file: open /var/tmp/check-gocryptfs/scratchdev/gocryptfs.conf: permission denied

After:

  $ gocryptfs -fsck .
  Cannot open config file: open /var/tmp/check-gocryptfs/scratchdev/gocryptfs.conf: permission denied
2018-07-23 22:25:40 +02:00
Jakob Unterwurzacher f316f1b2df fusefronted: disallow writes running concurrently with reads
As uncovered by xfstests generic/465, concurrent reads and writes
could lead to this,

  doRead 3015532: corrupt block #1039: stupidgcm: message authentication failed,

as the read could pick up a block that has not yet been completely written -
write() is not atomic!

Now writes take ContentLock exclusively, while reads take it shared,
meaning that multiple reads can run in parallel with each other, but
not with a write.

This also simplifies the file header locking.
2018-07-22 22:29:22 +02:00
Jakob Unterwurzacher c70df522d2 fusefrontend: doWrite: delete file header if first write fails
xfstests generic/083 fills the filesystem almost completely while
running fsstress in parallel. In fsck, these would show up:

  readFileID 2580: incomplete file, got 18 instead of 19 bytes

This could happen when writing the file header works, but writing
the actual data fails.

Now we kill the header again by truncating the file to zero.
2018-07-15 15:12:55 +02:00
Jakob Unterwurzacher 55bb22bad6 fusefrontend: doWrite: no need to take HeaderLock.RLock()
Other writers are blocked by ContentLock already.
2018-07-15 12:40:23 +02:00
Jakob Unterwurzacher bbf5b72fff WriteDirIV: delete incomplete gocryptfs.diriv file if write fails
If the underlying filesystem is full, writing to gocryptfs.diriv may
fail, and later fsck show this:

	OpenDir "xyz": could not read gocryptfs.diriv: wanted 16 bytes, got 0

Uncovered by xfstests generic/083.

Also fixes a fd leak in the error path.
2018-07-15 12:02:39 +02:00
Jakob Unterwurzacher bcca323cb7 contentenc: reserve one extra block in pool plaintext buffers
File holes and -fsck can cause unaligned read accesses, which means
we have to decrypt one extra plaintext block.

xfstests generic/083 manage to crash -fsck like this:

generic/083	2018/07/14 15:25:21 wrong len=266240, want=131072
panic: wrong len=266240, want=131072

goroutine 1 [running]:
log.Panicf(0x67fc00, 0x15, 0xc4204fec90, 0x2, 0x2)
	/usr/local/go/src/log/log.go:333 +0xda
github.com/rfjakob/gocryptfs/internal/contentenc.(*bPool).Put(0xc4200d4800, 0xc4202f2000, 0x21000, 0x41000)
	/home/jakob/go/src/github.com/rfjakob/gocryptfs/internal/contentenc/bpool.go:27 +0x15d
github.com/rfjakob/gocryptfs/internal/fusefrontend.(*File).doRead(0xc4200b4500, 0xc42019e000, 0x0, 0x20000, 0x28400, 0x20000, 0xc42019e000, 0xc4204ff008, 0x435164, 0xc420000180)
	/home/jakob/go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/file.go:227 +0xba9
github.com/rfjakob/gocryptfs/internal/fusefrontend.(*File).Read(0xc4200b4500, 0xc42019e000, 0x20000, 0x20000, 0x28400, 0x0, 0x0, 0x0)
	/home/jakob/go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/file.go:246 +0x23e
main.(*fsckObj).file(0xc420069320, 0xc42001a630, 0x21)
	/home/jakob/go/src/github.com/rfjakob/gocryptfs/fsck.go:126 +0x21f
main.(*fsckObj).dir(0xc420069320, 0xc420014dc0, 0x1d)
	/home/jakob/go/src/github.com/rfjakob/gocryptfs/fsck.go:76 +0x387
main.(*fsckObj).dir(0xc420069320, 0xc42021dae0, 0x19)
	/home/jakob/go/src/github.com/rfjakob/gocryptfs/fsck.go:74 +0x347
2018-07-15 11:39:19 +02:00