rfjakob / gocryptfs

Encrypted overlay filesystem written in Go
https://nuetzlich.net/gocryptfs/
MIT License
3.57k stars 253 forks source link

Mac OS X support #15

Closed rfjakob closed 7 years ago

rfjakob commented 8 years ago

Go support Mac OS X, as does the FUSE library we use, go-fuse.

gocrypts may actually work out of the box on OSX, but there probably are small issues that have to be sorted out.

At the very least, gocryptfs has to be tested on OSX. As I do not have a Mac to test on, this would be an opportunity for somebody from the Mac community to step up. Please comment here if you are interested.

hasit commented 8 years ago

I am interested in helping on this as much as I can. I will try to run it and comment back with what I find.

rfjakob commented 8 years ago

Hi @hasit, great to hear that!

netheril96 commented 8 years ago

One thing it might have omitted is encryption of extended attributes. OS X makes extensive usage of extended attributes. For example, when you download a file with Google Chrome or Safari, the file will be marked with its original URL. When I tried EncFS before, the encrypted file always had the same extended attributes as the decrypted one, and thereby the plaintext could be easily obtained. I suspect the encryption of extended attribute will never cross the mind of regular Linux folk.

rfjakob commented 8 years ago

Extended attributes are not implemented yet in gocryptfs. I don't know how big a problem that is on OSX, but at least we cannot leak data ;)

spaghetti2514 commented 8 years ago

Attempting to install on OS X 10.11.2 with go get github.com/rfjakob/gocryptfs, I get the following

# github.com/rfjakob/gocryptfs/cryptfs
.go/src/github.com/rfjakob/gocryptfs/cryptfs/openssl_aead.go:35: undefined: openssl.NewGCMEncryptionCipherCtx
.go/src/github.com/rfjakob/gocryptfs/cryptfs/openssl_aead.go:76: undefined: openssl.NewGCMDecryptionCipherCtx
# github.com/hanwen/go-fuse/fuse/nodefs
.go/src/github.com/hanwen/go-fuse/fuse/nodefs/files_darwin.go:5: imported and not used: "time"
.go/src/github.com/hanwen/go-fuse/fuse/nodefs/syscall.go:11: undefined: syscall.SYS_UTIMENSAT
rfjakob commented 8 years ago

@spaghetti2514 : Interesting. Can you run "openssl version" and post the output?

spaghetti2514 commented 8 years ago

@rfjakob OpenSSL 1.0.2e 3 Dec 2015

spaghetti2514 commented 8 years ago

I should point out that this probably has more to do with https://github.com/spacemonkeygo/openssl/blob/master/ciphers_gcm.go#L15 than my openssl version

Removing the ",!darwin" part of that line eliminates those two errors for me

rfjakob commented 8 years ago

I guess the "!darwin" is because openssl was too old in an earlier OSX version. But 1.0.2e is very recent, can you file a bug against spacemonkeygo/openssl?

On Thu, Jan 7, 2016 at 1:34 AM, spaghetti2514 notifications@github.com wrote:

I should point out that this probably has more to do with https://github.com/spacemonkeygo/openssl/blob/master/ciphers_gcm.go#L15 than my openssl version

Removing the ",!darwin" part of that line eliminates those two errors for me

— Reply to this email directly or view it on GitHub https://github.com/rfjakob/gocryptfs/issues/15#issuecomment-169509424.

spaghetti2514 commented 8 years ago

1.0.2e is very recent because I installed it very recently. It is not the native OS X openssl because the native OS X openssl no longer exists. Apple deprecated the use of openssl a long time ago in favor of their own crypto libs, and finally stopped shipping openssl completely in 10.11. OS X users that still build things against openssl tend to install it from homebrew, an unofficial package manager for OS X.

I am unsure if excluding OS X in the build process should be considered a bug, since the only reason it works for me is that I'm building openssl myself via homebrew. On the other hand, there is no longer an official openssl shipped with OS X at all, so maybe that should be assumed. Still want me to open a bug report?

rfjakob commented 8 years ago

In that case, it makes no sense at all anymore to exclude gcm from the build. Yes please file a ticket.

I will take care of the other two issues as I am afraid I have caused them.

spaghetti2514 commented 8 years ago

I have filed a ticket.

What other two issues are you referring to? just the unused time import and SYS_UTIMENSAT problems in go-fuse?

I think we'll run into other problems after that, as commenting some of that out to try to get farther along in the build reveals other build errors, but I can't be certain that they're not being caused by the way I'm stepping around previous errors. Would you like me to wait until you've properly fixed the SYS_UTIMENSAT issue before checking for other errors?

rfjakob commented 8 years ago

Yes, just the two in go-fuse. Commenting them out should be fine. Later build problems are probably real, what do you get? On Jan 7, 2016 02:23, "spaghetti2514" notifications@github.com wrote:

I have filed a ticket.

What other two issues are you referring to? just the unused time import and SYS_UTIMENSAT problems in go-fuse?

I think we'll run into other problems after that, as commenting some of that out to try to get farther along in the build reveals other build errors, but I can't be certain that they're not being caused by the way I'm stepping around previous errors. Would you like me to wait until you've properly fixed the SYS_UTIMENSAT issue before checking for other errors?

— Reply to this email directly or view it on GitHub https://github.com/rfjakob/gocryptfs/issues/15#issuecomment-169516383.

spaghetti2514 commented 8 years ago

After bypassing SYS_UTIMENSAT in syscall.go I get

# github.com/hanwen/go-fuse/fuse/pathfs
.go/src/github.com/hanwen/go-fuse/fuse/pathfs/loopback.go:140: undefined: sysUtimensat
.go/src/github.com/hanwen/go-fuse/fuse/pathfs/loopback.go:140: undefined: _AT_SYMLINK_NOFOLLOW

After commenting out line 140 in loopback.go and changing the return err to return 0, I get

# github.com/rfjakob/gocryptfs/pathfs_frontend
.go/src/github.com/rfjakob/gocryptfs/pathfs_frontend/file.go:213: undefined: syscall.Fallocate

After replacing line 213 in file.go with err = syscall.EINTR, the build succeeds.

rfjakob commented 8 years ago

Ok, I hope I have fixed all of this, but I do not have a Mac to test on. @spaghetti2514 , can you 1) "git pull" in gocryptfs 2) Replace hanwen/go-fuse with my branch that has the OSX build fix: https://github.com/rfjakob/go-fuse . I will get it upstream once you confirm it fixes the issue (and works).

spaghetti2514 commented 8 years ago

@rfjakob

go-fuse/fuse/nodefs/files_darwin.go:74: cannot use int64(t.Nanosecond() / 1000) (type int64) as type int32 in assignment

Edit: bypassing that leads to

go-fuse/fuse/pathfs/loopback_darwin.go:44: syntax error: unexpected name, expecting )
rfjakob commented 8 years ago

Thanks, should be fixed, please pull go-fuse.

spaghetti2514 commented 8 years ago
# github.com/rfjakob/go-fuse/fuse/pathfs
.go/src/github.com/rfjakob/go-fuse/fuse/pathfs/loopback_darwin.go:33: undefined: time in time.Time
.go/src/github.com/rfjakob/go-fuse/fuse/pathfs/loopback_darwin.go:42: undefined: time in time.Time
.go/src/github.com/rfjakob/go-fuse/fuse/pathfs/loopback_darwin.go:56: undefined: f in f.lock
.go/src/github.com/rfjakob/go-fuse/fuse/pathfs/loopback_darwin.go:58: undefined: f in f.lock
spaghetti2514 commented 8 years ago

Other various things

go-fuse/fuse/pathfs/loopback_darwin.go:35: cannot use int64(t.Nanosecond() / 1000) (type int64) as type int32 in assignment
gocryptfs/pathfs_frontend/compat_darwin.go:3: imported and not used: "syscall"
gocryptfs/pathfs_frontend/compat_darwin.go:13: missing return at end of function
rfjakob commented 8 years ago

Ok, I need a cross compiler ;) I will get back to you once I have it building.

rfjakob commented 8 years ago

Turns out that for cross compilation to work, I would need the C header files from OSX, because go-fuse uses cgo. And to get those, I'd have to extract them from XCode on a running OSX machine. OMG.

@spaghetti2514 : The things you have reported should be fixed, please pull. If you still have the patience, I think we are done soon.

hasit commented 8 years ago

I can confirm the same error. Following is the output I get on my MacBook Pro (Retina, 13-inch, Late 2013) OSX El Capitan version 10.11.2 .

# github.com/hanwen/go-fuse/fuse/nodefs
go/src/github.com/hanwen/go-fuse/fuse/nodefs/files_darwin.go:5: imported and not used: "time"
go/src/github.com/hanwen/go-fuse/fuse/nodefs/syscall.go:11: undefined: syscall.SYS_UTIMENSAT
# github.com/spacemonkeygo/openssl
go/src/github.com/spacemonkeygo/openssl/bio.go:21:10: fatal error: 'openssl/bio.h' file not found
#include <openssl/bio.h>
         ^
1 error generated.
rfjakob commented 8 years ago

Hasit, you need to replace go-fuse with my branch, and you need openssl installed. The errors you see are already fixed.

spaghetti2514 commented 8 years ago

@rfjakob Build succeeds with latest changes

rfjakob commented 8 years ago

Great. Pushed to upstream as https://github.com/hanwen/go-fuse/pull/89 .

./test.bash ?

spaghetti2514 commented 8 years ago
ok      github.com/rfjakob/gocryptfs/cryptfs    1.886s
gocryptfs v0.7.1; on-disk format 2
remove /tmp/gocryptfs_main_test//TestExampleFsV04: resource busy
FAIL    github.com/rfjakob/gocryptfs/integration_tests  0.055s

Edit: That was caused by running the script twice when the first one failed to unmount any of the temporary filesystems. After unmounting the filesystems in /tmp and trying again I got

ok      github.com/rfjakob/gocryptfs/cryptfs    1.828s
gocryptfs v0.7.1; on-disk format 2
--- FAIL: TestExampleFSv04 (0.96s)
    example_filesystems_test.go:21: open /tmp/gocryptfs_main_test/TestExampleFsV04/status.txt: no such file or directory
--- FAIL: TestExampleFSv05 (0.14s)
    example_filesystems_test.go:21: open /tmp/gocryptfs_main_test/TestExampleFsV05/status.txt: no such file or directory
--- FAIL: TestExampleFSv06 (0.12s)
    example_filesystems_test.go:21: open /tmp/gocryptfs_main_test/TestExampleFsV06/status.txt: no such file or directory
--- FAIL: TestExampleFSv06PlaintextNames (0.10s)
    example_filesystems_test.go:21: open /tmp/gocryptfs_main_test/TestExampleFsV06PlaintextNames/status.txt: no such file or directory
exec: "fusermount": executable file not found in $PATH
exit status 10
FAIL    github.com/rfjakob/gocryptfs/integration_tests  3.267s

fusermount is linux-specific by the way. Normal umount works fine for fuse filesystems on OS X

spaghetti2514 commented 8 years ago

@rfjakob The OS X issue at spacemonkeygo/openssl has not been addressed at all in months. Would you consider forking it, making the small change yourself, and having gocryptfs depend on your fork instead? Considering how infrequently changes are made to the repo, it shouldn't be much effort at all for you to "maintain" and would allow you to address issues like this much more efficiently.

rfjakob commented 8 years ago

@spaghetti2514 gocryptfs v0.10, released a month ago, replaced the dependency to spacemonkeygo/openssl with our own minimal wrapper, stupidgcm. So this problem should be gone (but maybe we gained other ones ;) ).

The example filesystem failures look look pretty bad, though. Does gocryptfs work at all?

rfjakob commented 8 years ago

BTW since commit https://github.com/rfjakob/gocryptfs/commit/d5b7eb33daec612626305c961b7ec6d5eccd79a7 I am calling umount on OSX.

spaghetti2514 commented 8 years ago
# github.com/rfjakob/gocryptfs/internal/nametransform
.go/src/github.com/rfjakob/gocryptfs/internal/nametransform/diriv.go:38: undefined: syscall.Openat
.go/src/github.com/rfjakob/gocryptfs/internal/nametransform/longnames.go:68: undefined: syscall.Unlinkat
.go/src/github.com/rfjakob/gocryptfs/internal/nametransform/longnames.go:89: undefined: syscall.Openat

Edit: After bypassing the above:

# github.com/rfjakob/gocryptfs/internal/fusefrontend
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/file_allocate_truncate.go:62: undefined: syscall.Fallocate
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs.go:135: undefined: syscall.Openat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs.go:207: undefined: syscall.Mknodat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs.go:297: undefined: syscall.Unlinkat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs.go:410: undefined: syscall.Renameat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs.go:419: undefined: syscall.Renameat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs_dir.go:116: undefined: syscall.Openat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs_dir.go:138: undefined: syscall.Openat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs_dir.go:171: undefined: syscall.Renameat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs_dir.go:185: undefined: syscall.Renameat
.go/src/github.com/rfjakob/gocryptfs/internal/fusefrontend/fs_dir.go:185: too many errors

Edit Edit: Build succeeds after additionally bypassing the above. I'm not going to run the tests though as I'm pretty confident nothing will work with a commented out fallocate and a bunch of *at syscalls being replaced with their non-at version and with file descriptors removed

rfjakob commented 8 years ago

Oh dear, OSX does not have the openat syscall. Fun times.

rfjakob commented 8 years ago

This has Fallocate and Openat fixed: https://github.com/rfjakob/gocryptfs/commit/9b725c15cf50cfb85ec6ec88c47843092775dedc Working on Renameat.

rfjakob commented 8 years ago

But it broke Prealloc. Fixing in the next patch.

rfjakob commented 8 years ago

Ok, I think I got everything. Please try latest master ( 741bf0726e71c931af1dc1278571c280fc27970f ).

spaghetti2514 commented 8 years ago

Builds successfully though with the following:

# github.com/rfjakob/gocryptfs/internal/stupidgcm
.go/src/github.com/rfjakob/gocryptfs/internal/stupidgcm/locking.go:16:2: warning: indirection of non-volatile null pointer will be deleted, not trap [-Wnull-dereference]
.go/src/github.com/rfjakob/gocryptfs/internal/stupidgcm/locking.go:16:2: note: consider using __builtin_trap() or qualifying pointer with 'volatile'

Resulting binary seems to work but often prints open /proc/cpuinfo: no such file or directory

All of test.bash:

open /proc/cpuinfo: no such file or directory
gocryptfs v0.12-44-g77e7abd; go-fuse 7b28148; 2016-07-04 go1.6.2
?       github.com/rfjakob/gocryptfs    [no test files]
ok      github.com/rfjakob/gocryptfs/internal/configfile    2.406s
ok      github.com/rfjakob/gocryptfs/internal/contentenc    0.033s
ok      github.com/rfjakob/gocryptfs/internal/cryptocore    0.033s
?       github.com/rfjakob/gocryptfs/internal/fusefrontend  [no test files]
ok      github.com/rfjakob/gocryptfs/internal/nametransform 0.023s
ok      github.com/rfjakob/gocryptfs/internal/prefer_openssl    0.019s
ok      github.com/rfjakob/gocryptfs/internal/readpassword  0.168s
# github.com/rfjakob/gocryptfs/tests/test_helpers
tests/test_helpers/helpers.go:301: invalid operation: st.Blocks * st.Blksize (mismatched types int64 and int32)
# github.com/rfjakob/gocryptfs/internal/stupidgcm
internal/stupidgcm/locking.go:16:2: warning: indirection of non-volatile null pointer will be deleted, not trap [-Wnull-dereference]
internal/stupidgcm/locking.go:16:2: note: consider using __builtin_trap() or qualifying pointer with 'volatile'
ok      github.com/rfjakob/gocryptfs/internal/stupidgcm 1.434s
?       github.com/rfjakob/gocryptfs/internal/syscallcompat [no test files]
?       github.com/rfjakob/gocryptfs/internal/tlog  [no test files]
FAIL    github.com/rfjakob/gocryptfs/tests/example_filesystems [build failed]
FAIL    github.com/rfjakob/gocryptfs/tests/matrix [build failed]
FAIL    github.com/rfjakob/gocryptfs/tests/normal [build failed]
FAIL    github.com/rfjakob/gocryptfs/tests/plaintextnames [build failed]
rfjakob commented 8 years ago

Does not look bad, but obviously most of the tests have not been run. I have fixed that in https://github.com/rfjakob/gocryptfs/commit/9d17fdb2068a5217ffab260db671c1cc50536e04 and also got rid of the /proc/cpuinfo warnings.

spaghetti2514 commented 8 years ago

Tests seem to be hanging somewhere in tests/example_filesystems df shows currently mounted filesystems named v0.7, v0.7-plaintextnames.mnt, and v0.9 under one directory, and default-plain under another if that helps you diagnose how far the tests have progressed at all.

Oh wait, free inode count dropped for each of them after several minutes. I guess the tests are working, just very slowly. I'll post the full output tomorrow if it finishes.

Edit: after no progress in 10 hours I think it's safe to assume these aren't finishing. Is there a way to run tests more verbosely to see where it's hanging?

spaghetti2514 commented 8 years ago

@rfjakob just for the record, you referenced this issue as "ticket #25" and "ticket #" in the 1.0-rc1 README update even though both links correctly go to this issue (#15)

rfjakob commented 8 years ago

Fixed in the README, thanks!

You can run ./test.bash -v, this will at least show each test being run.

Also, sorry for replying so late - github does not send out notifications when a post is edited. I only noticed your edit about the hanging tests right now when replying to the README issues.

spaghetti2514 commented 8 years ago

I don't think -v is helping. It's more verbose, but it's not printing any information about what's going on right before the hang

last line printed before hanging is

?       github.com/rfjakob/gocryptfs/internal/tlog    [no test files]
rfjakob commented 8 years ago

Ok I guess it hangs in the Init() of the next test. How about

 ./test.bash -v -timeout 60s

? I hope this gets us a backtrace for the hung location.

rfjakob commented 8 years ago

Or maybe not. This should have already triggered. Looks like it does affect time spent in Init().

-timeout t If a test runs longer than t, panic. The default is 10

minutes (10m).

I'll add more debugging info tonight.

rfjakob commented 8 years ago

"Looks like it does NOT affect time spent in Init()"

rfjakob commented 8 years ago

@spaghetti2514 please try again, I have fixed a bug (the cleanup function was calling fusermount instead of umount on OSX) and added output for the Init function (actually it is called TestMain). Enable with -v.

spaghetti2514 commented 8 years ago

Last output is still

?       github.com/rfjakob/gocryptfs/internal/tlog  [no test files]

before it hangs. ctrl+c after a while lets it continue (which I'm pretty sure it wasn't doing before) with

^Cexample_filesystems: testing with "-openssl=false"

Backtrace:

umount(/private/tmp/gocryptfs-test-parent/053481967/default-plain): Resource busy -- try 'diskutil unmount'
exit status 1
panic: exit status 1

goroutine 1 [running]:
panic(0x4255e80, 0xc82024cbe0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/panic.go:481 +0x3e6
github.com/rfjakob/gocryptfs/tests/test_helpers.UnmountPanic(0xc8200147c0, 0x32)
    ~/.go/src/github.com/rfjakob/gocryptfs/tests/test_helpers/helpers.go:153 +0x110
github.com/rfjakob/gocryptfs/tests/matrix.TestMain(0xc82004fef8)
    ~/.go/src/github.com/rfjakob/gocryptfs/tests/matrix/matrix_test.go:48 +0x628
main.main()
    github.com/rfjakob/gocryptfs/tests/matrix/_test/_testmain.go:78 +0x114
FAIL    github.com/rfjakob/gocryptfs/tests/matrix   105.947s
rprieto commented 8 years ago

I'm progressing on my journey to build on macOS from source, and just hit this one

⇒  ./build-without-openssl.bash
# github.com/rfjakob/gocryptfs/internal/fusefrontend_reverse
internal/fusefrontend_reverse/rfs.go:138: cannot use st.Dev (type int32) as type uint64 in field value

It could be a red herring but Stat_t.Dev is documented as a unit64, but the macOS amd64 source says int32. I am building on go version go1.7.1 darwin/amd64.

Any ideas? The introduction of fusefrontend_reverse looks quite recent.

rfjakob commented 8 years ago

Yes, fusefrontend_reverse is very new! You are the first one to build it on OSX ;)

We need to cast st.Dev to uint64, in other words, please replace "st.Dev" with "uint64(st.Dev)" and see if anything else fails.

rprieto commented 8 years ago

Perfect, thanks for the quick reply! Everything builds fine now. I also got around it by changing type devIno struct to use int32 but that would break a few things on Linux :)

rfjakob commented 8 years ago

Yes probably :)

But if you want to submit a pull request with the uint64 cast I will merge it right away.

rprieto commented 8 years ago

Making progress. Creating a folder works well, but mounting crashes with:

panic: darwin has no splice

This comes from fuse/splice_darwin.go which is not implemented. Is splice required at all for gocryptfs? Should I use a different version of Fuse for macOS (currently using 3.5.2)?