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).
This commit is contained in:
Sebastian Lackner 2019-01-05 15:44:32 +01:00 committed by Jakob Unterwurzacher
parent ad15ad9985
commit 7e05e809b7
4 changed files with 61 additions and 25 deletions

View File

@ -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"

View File

@ -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)
}

View File

@ -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))
}

25
main.go
View File

@ -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)
}