summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2018-06-07 22:50:30 +0200
committerJakob Unterwurzacher2018-06-07 22:50:30 +0200
commit53d6a9999dd0e4c31636d16179f284fff35a35d9 (patch)
treed2a41d46e397fcfc57c9d2da87baf9599b972704
parente29a81efc3df88b451a4a9464724a952d97b4115 (diff)
main: accept -dev, -nodev, -suid, -nosuid, -exec, -noexec
When mounted via /etc/fstab like this, /a /b fuse.gocryptfs default 0 0 we always get extra options passed. As reported by @mahkoh at https://github.com/rfjakob/gocryptfs/pull/233 : mount passes `-o noexec` if `-o user` is set and `-o exec` is not set. If both `-o user` and `-o exec` are set, it passes `-o exec`. Make these options work, and in addtion, also make -suid and -rw work the same way. Reported-by: @mahkoh
-rw-r--r--cli_args.go22
-rw-r--r--daemonize.go4
-rw-r--r--mount.go20
-rw-r--r--tests/cli/cli_test.go24
-rw-r--r--tests/test_helpers/helpers.go11
5 files changed, 66 insertions, 15 deletions
diff --git a/cli_args.go b/cli_args.go
index 6253c14..76876d6 100644
--- a/cli_args.go
+++ b/cli_args.go
@@ -20,9 +20,11 @@ import (
type argContainer struct {
debug, init, zerokey, fusedebug, openssl, passwd, fg, version,
plaintextnames, quiet, nosyslog, wpanic,
- longnames, allow_other, ro, reverse, aessiv, nonempty, raw64,
+ longnames, allow_other, reverse, aessiv, nonempty, raw64,
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
sharedstorage, devrandom, fsck bool
+ // Mount options with opposites
+ dev, nodev, suid, nosuid, exec, noexec, rw, ro bool
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string
// Configuration file name override
@@ -121,7 +123,6 @@ func parseCliOpts() (args argContainer) {
flagSet.BoolVar(&args.longnames, "longnames", true, "Store names longer than 176 bytes in extra files")
flagSet.BoolVar(&args.allow_other, "allow_other", false, "Allow other users to access the filesystem. "+
"Only works if user_allow_other is set in /etc/fuse.conf.")
- flagSet.BoolVar(&args.ro, "ro", false, "Mount the filesystem read-only")
flagSet.BoolVar(&args.reverse, "reverse", false, "Reverse mode")
flagSet.BoolVar(&args.aessiv, "aessiv", false, "AES-SIV encryption")
flagSet.BoolVar(&args.nonempty, "nonempty", false, "Allow mounting over non-empty directories")
@@ -137,6 +138,17 @@ func parseCliOpts() (args argContainer) {
flagSet.BoolVar(&args.sharedstorage, "sharedstorage", false, "Make concurrent access to a shared CIPHERDIR safer")
flagSet.BoolVar(&args.devrandom, "devrandom", false, "Use /dev/random for generating master key")
flagSet.BoolVar(&args.fsck, "fsck", false, "Run a filesystem check on CIPHERDIR")
+
+ // Mount options with opposites
+ flagSet.BoolVar(&args.dev, "dev", false, "Allow device files")
+ flagSet.BoolVar(&args.nodev, "nodev", false, "Deny device files")
+ flagSet.BoolVar(&args.suid, "suid", false, "Allow suid binaries")
+ flagSet.BoolVar(&args.nosuid, "nosuid", false, "Deny suid binaries")
+ flagSet.BoolVar(&args.exec, "exec", false, "Allow executables")
+ flagSet.BoolVar(&args.noexec, "noexec", false, "Deny executables")
+ flagSet.BoolVar(&args.rw, "rw", false, "Mount the filesystem read-write")
+ flagSet.BoolVar(&args.ro, "ro", false, "Mount the filesystem read-only")
+
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
flagSet.StringVar(&args.memprofile, "memprofile", "", "Write memory profile to specified file")
@@ -152,12 +164,6 @@ func parseCliOpts() (args argContainer) {
"successful mount - used internally for daemonization")
flagSet.IntVar(&args.scryptn, "scryptn", configfile.ScryptDefaultLogN, "scrypt cost parameter logN. Possible values: 10-28. "+
"A lower value speeds up mounting and reduces its memory needs, but makes the password susceptible to brute-force attacks")
- // Ignored otions
- var dummyBool bool
- ignoreText := "(ignored for compatibility)"
- flagSet.BoolVar(&dummyBool, "rw", false, ignoreText)
- flagSet.BoolVar(&dummyBool, "nosuid", false, ignoreText)
- flagSet.BoolVar(&dummyBool, "nodev", false, ignoreText)
var dummyString string
flagSet.StringVar(&dummyString, "o", "", "For compatibility with mount(1), options can be also passed as a comma-separated list to -o on the end.")
// Actual parsing
diff --git a/daemonize.go b/daemonize.go
index 03c4fc4..abb6d08 100644
--- a/daemonize.go
+++ b/daemonize.go
@@ -37,7 +37,7 @@ func forkChild() int {
exitOnUsr1()
err := c.Start()
if err != nil {
- tlog.Fatal.Printf("forkChild: starting %s failed: %v\n", name, err)
+ tlog.Fatal.Printf("forkChild: starting %s failed: %v", name, err)
return exitcodes.ForkChild
}
err = c.Wait()
@@ -47,7 +47,7 @@ func forkChild() int {
os.Exit(waitstat.ExitStatus())
}
}
- tlog.Fatal.Printf("forkChild: wait returned an unknown error: %v\n", err)
+ tlog.Fatal.Printf("forkChild: wait returned an unknown error: %v", err)
return exitcodes.ForkChild
}
// The child exited with 0 - let's do the same.
diff --git a/mount.go b/mount.go
index 54ceedc..cbe77b4 100644
--- a/mount.go
+++ b/mount.go
@@ -314,17 +314,33 @@ func initGoFuse(fs pathfs.FileSystem, args *argContainer) *fuse.Server {
if args.reverse {
mOpts.Name += "-reverse"
}
-
// Add a volume name if running osxfuse. Otherwise the Finder will show it as
// something like "osxfuse Volume 0 (gocryptfs)".
if runtime.GOOS == "darwin" {
mOpts.Options = append(mOpts.Options, "volname="+path.Base(args.mountpoint))
}
-
// The kernel enforces read-only operation, we just have to pass "ro".
// Reverse mounts are always read-only.
if args.ro || args.reverse {
mOpts.Options = append(mOpts.Options, "ro")
+ } else if args.rw {
+ mOpts.Options = append(mOpts.Options, "rw")
+ }
+ // If both "nosuid" and "suid" were passed, the safer option wins.
+ if args.nosuid {
+ mOpts.Options = append(mOpts.Options, "nosuid")
+ } else if args.suid {
+ mOpts.Options = append(mOpts.Options, "suid")
+ }
+ if args.nodev {
+ mOpts.Options = append(mOpts.Options, "nodev")
+ } else if args.dev {
+ mOpts.Options = append(mOpts.Options, "dev")
+ }
+ if args.noexec {
+ mOpts.Options = append(mOpts.Options, "noexec")
+ } else if args.exec {
+ mOpts.Options = append(mOpts.Options, "exec")
}
// Add additional mount options (if any) after the stock ones, so the user has
// a chance to override them.
diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go
index 8808742..5508360 100644
--- a/tests/cli/cli_test.go
+++ b/tests/cli/cli_test.go
@@ -449,6 +449,30 @@ func TestMultipleOperationFlags(t *testing.T) {
}
}
+func TestNoexec(t *testing.T) {
+ dir := test_helpers.InitFS(t)
+ mnt := dir + ".mnt"
+ err := os.Mkdir(mnt, 0700)
+ if err != nil {
+ t.Fatal(err)
+ }
+ test_helpers.MountOrFatal(t, dir, mnt, "-extpass=echo test", "-noexec")
+ defer test_helpers.UnmountPanic(mnt)
+ sh := mnt + "/x.sh"
+ content := `#!/bin/bash
+echo hello
+`
+ err = ioutil.WriteFile(sh, []byte(content), 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = exec.Command(sh).Run()
+ exitCode := test_helpers.ExtractCmdExitCode(err)
+ if exitCode != int(syscall.EACCES) {
+ t.Errorf("got exitcode %d instead of EPERM (%d)", exitCode, syscall.EPERM)
+ }
+}
+
// Test that a missing argument to "-o" triggers exit code 1.
// See also cli_args_test.go for comprehensive tests of "-o" parsing.
func TestMissingOArg(t *testing.T) {
diff --git a/tests/test_helpers/helpers.go b/tests/test_helpers/helpers.go
index e7fcf4b..ef748e2 100644
--- a/tests/test_helpers/helpers.go
+++ b/tests/test_helpers/helpers.go
@@ -433,9 +433,14 @@ func ExtractCmdExitCode(err error) int {
return 0
}
// OMG this is convoluted
- err2 := err.(*exec.ExitError)
- code := err2.Sys().(syscall.WaitStatus).ExitStatus()
- return code
+ if err2, ok := err.(*exec.ExitError); ok {
+ return err2.Sys().(syscall.WaitStatus).ExitStatus()
+ }
+ if err2, ok := err.(*os.PathError); ok {
+ return int(err2.Err.(syscall.Errno))
+ }
+ log.Panicf("could not decode error %#v", err)
+ return 0
}
// ListFds lists our open file descriptors.