From 7e05e809b7579ad0473fff6ce466c19d417d4e93 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 5 Jan 2019 15:44:32 +0100 Subject: [PATCH] main: Run 'ensure fds' code early during the program startup. The files are apparently processed in alphabetic order, so cli_args.go is processed before main.go. In order to run before the go-fuse imports, put the 'ensure fds' code in a separate package. Debug messages are omitted to avoid additional imports (that might contain other code messing up our file descriptors). --- cli_args.go | 5 +++ internal/ensurefds012/ensurefds012.go | 52 +++++++++++++++++++++++++++ internal/fusefrontend/dircache.go | 4 +++ main.go | 25 ------------- 4 files changed, 61 insertions(+), 25 deletions(-) create mode 100644 internal/ensurefds012/ensurefds012.go diff --git a/cli_args.go b/cli_args.go index b3f2834..a4da85c 100644 --- a/cli_args.go +++ b/cli_args.go @@ -1,5 +1,10 @@ package main +// Should be initialized before anything else. +// This import line MUST be in the alphabitcally first source code file of +// package main! +import _ "github.com/rfjakob/gocryptfs/internal/ensurefds012" + import ( "flag" "fmt" diff --git a/internal/ensurefds012/ensurefds012.go b/internal/ensurefds012/ensurefds012.go new file mode 100644 index 0000000..7872eb2 --- /dev/null +++ b/internal/ensurefds012/ensurefds012.go @@ -0,0 +1,52 @@ +package ensurefds012 + +// Package ensurefds012 ensures that file descriptors 0,1,2 are open. It opens +// multiple copies of /dev/null as required. +// The Go stdlib as well as the gocryptfs code rely on the fact that +// fds 0,1,2 are always open. +// +// Use like this: +// +// import _ "github.com/rfjakob/gocryptfs/internal/ensurefds012" +// +// The import line MUST be in the alphabitcally first source code file of +// package main! +// +// You can test if it works as expected by inserting a long sleep into main, +// startings gocryptfs with all fds closed like this, +// +// $ ./gocryptfs 0<&- 1>&- 2>&- +// +// and then checking the open fds. It should look like this: +// +// $ ls -l /proc/$(pgrep gocryptfs)/fd +// total 0 +// lrwx------. 1 jakob jakob 64 Jan 5 15:54 0 -> /dev/null +// lrwx------. 1 jakob jakob 64 Jan 5 15:54 1 -> /dev/null +// lrwx------. 1 jakob jakob 64 Jan 5 15:54 2 -> /dev/null +// l-wx------. 1 jakob jakob 64 Jan 5 15:54 3 -> /dev/null +// lrwx------. 1 jakob jakob 64 Jan 5 15:54 4 -> 'anon_inode:[eventpoll]' +// +// See https://github.com/rfjakob/gocryptfs/issues/320 for details. + +import ( + "os" + "syscall" + + "github.com/rfjakob/gocryptfs/internal/exitcodes" +) + +func init() { + fd, err := syscall.Open("/dev/null", syscall.O_RDWR, 0) + if err != nil { + os.Exit(exitcodes.DevNull) + } + for fd <= 2 { + fd, err = syscall.Dup(fd) + if err != nil { + os.Exit(exitcodes.DevNull) + } + } + // Close excess fd (usually fd 3) + syscall.Close(fd) +} diff --git a/internal/fusefrontend/dircache.go b/internal/fusefrontend/dircache.go index 6d0d570..68fd99c 100644 --- a/internal/fusefrontend/dircache.go +++ b/internal/fusefrontend/dircache.go @@ -35,6 +35,8 @@ type dirCacheEntryStruct struct { func (e *dirCacheEntryStruct) Clear() { // An earlier clear may have already closed the fd, or the cache // has never been filled (fd is 0 in that case). + // Note: package ensurefds012, imported from main, guarantees that dirCache + // can never get fds 0,1,2. if e.fd > 0 { err := syscall.Close(e.fd) if err != nil { @@ -72,6 +74,8 @@ func (d *dirCacheStruct) Clear() { // Store the entry in the cache. The passed "fd" will be Dup()ed, and the caller // can close their copy at will. func (d *dirCacheStruct) Store(dirRelPath string, fd int, iv []byte) { + // Note: package ensurefds012, imported from main, guarantees that dirCache + // can never get fds 0,1,2. if fd <= 0 || len(iv) != nametransform.DirIVLen { log.Panicf("Store sanity check failed: fd=%d len=%d", fd, len(iv)) } diff --git a/main.go b/main.go index 619b1ce..a376356 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ import ( "runtime" "strconv" "strings" - "syscall" "github.com/hanwen/go-fuse/fuse" @@ -150,7 +149,6 @@ func printVersion() { } func main() { - ensureStdFds() mxp := runtime.GOMAXPROCS(0) if mxp < 4 { // On a 2-core machine, setting maxprocs to 4 gives 10% better performance @@ -330,26 +328,3 @@ func main() { os.Exit(0) } } - -// ensureStdFds ensures that file descriptors 0,1,2 are open. The Go stdlib, -// as well as the gocryptfs code, relies on the fact that fds 0,1,2 are always -// open. -// See https://github.com/rfjakob/gocryptfs/issues/320 for details. -// -// This function should be called as the first thing from main(). -func ensureStdFds() { - fd, err := syscall.Open("/dev/null", syscall.O_RDWR, 0) - if err != nil { - tlog.Fatal.Printf("ensureStdFds: open /dev/null failed: %v", err) - os.Exit(exitcodes.DevNull) - } - for fd <= 2 { - fd, err = syscall.Dup(fd) - if err != nil { - tlog.Fatal.Printf("ensureStdFds: dup failed: %v", err) - os.Exit(exitcodes.DevNull) - } - } - // Close excess fd (usually fd 3) - syscall.Close(fd) -}