diff options
| -rw-r--r-- | .github/workflows/ci.yml | 2 | ||||
| -rw-r--r-- | internal/configfile/feature_flags.go | 11 | ||||
| -rw-r--r-- | mount.go | 26 |
3 files changed, 30 insertions, 9 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 792b879..fb55979 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: # Build & upload static binary - run: ./build-without-openssl.bash - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 with: name: gocryptfs ${{ github.sha }} static ${{ runner.arch }} binary, Go ${{ matrix.go }} path: gocryptfs diff --git a/internal/configfile/feature_flags.go b/internal/configfile/feature_flags.go index d6627a5..d5bd6d4 100644 --- a/internal/configfile/feature_flags.go +++ b/internal/configfile/feature_flags.go @@ -1,5 +1,9 @@ package configfile +import ( + "slices" +) + type flagIota int const ( @@ -64,10 +68,5 @@ func isFeatureFlagKnown(flag string) bool { // IsFeatureFlagSet returns true if the feature flag "flagWant" is enabled. func (cf *ConfFile) IsFeatureFlagSet(flagWant flagIota) bool { flagString := knownFlags[flagWant] - for _, flag := range cf.FeatureFlags { - if flag == flagString { - return true - } - } - return false + return slices.Contains(cf.FeatureFlags, flagString) } @@ -449,9 +449,18 @@ func initGoFuse(rootNode fs.InodeEmbedder, args *argContainer) *fuse.Server { if runtime.GOOS == "darwin" { opts["volname"] = strings.Replace(path.Base(args.mountpoint), ",", "_", -1) } + underlyingFilesystemRo, err := isReadOnlyFilesystem(args.cipherdir) + if err != nil { + tlog.Debug.Printf("Error checking if cipherdir is on a read-only filesystem: %s", err) + } else if underlyingFilesystemRo && args.rw { + tlog.Fatal.Printf("Writeable mount explicitly requested but cipherdir %s is on a read-only filesystem, refusing.", args.cipherdir) + os.Exit(exitcodes.Usage) + } else if underlyingFilesystemRo && !args.ro { + tlog.Info.Printf("Cipherdir %s is on a read-only filesystem, mounting as read-only.", args.cipherdir) + } // The kernel enforces read-only operation, we just have to pass "ro". - // Reverse mounts are always read-only. - if args.ro || args.reverse { + // Reverse mounts and mounts with cipherdirs on read-only filesystems are always read-only. + if args.ro || args.reverse || underlyingFilesystemRo { opts["ro"] = "" } else if args.rw { opts["rw"] = "" @@ -562,3 +571,16 @@ func unmount(srv *fuse.Server, mountpoint string) { } } } + +const ( + ST_RDONLY = 0x1 +) + +func isReadOnlyFilesystem(path string) (bool, error) { + var stat syscall.Statfs_t + if err := syscall.Statfs(path, &stat); err != nil { + return false, err + } + + return (stat.Flags & ST_RDONLY) != 0, nil +} |
