Add -acl flag to enable ACL enforcement

With test to verify that it actually works this
time: Run "make root_test".

Depends-on: https://github.com/rfjakob/gocryptfs/issues/536
Fixes: https://github.com/rfjakob/gocryptfs/issues/536
This commit is contained in:
Jakob Unterwurzacher 2021-05-08 17:17:08 +02:00
parent a91ad29d36
commit 86d8336b43
3 changed files with 87 additions and 1 deletions

View File

@ -30,7 +30,7 @@ type argContainer struct {
noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info, noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info,
sharedstorage, devrandom, fsck bool sharedstorage, devrandom, fsck bool
// Mount options with opposites // Mount options with opposites
dev, nodev, suid, nosuid, exec, noexec, rw, ro, kernel_cache bool dev, nodev, suid, nosuid, exec, noexec, rw, ro, kernel_cache, acl bool
masterkey, mountpoint, cipherdir, cpuprofile, masterkey, mountpoint, cipherdir, cpuprofile,
memprofile, ko, ctlsock, fsname, force_owner, trace, fido2 string memprofile, ko, ctlsock, fsname, force_owner, trace, fido2 string
// -extpass, -badname, -passfile can be passed multiple times // -extpass, -badname, -passfile can be passed multiple times
@ -180,6 +180,7 @@ func parseCliOpts() (args argContainer) {
flagSet.BoolVar(&args.rw, "rw", false, "Mount the filesystem read-write") flagSet.BoolVar(&args.rw, "rw", false, "Mount the filesystem read-write")
flagSet.BoolVar(&args.ro, "ro", false, "Mount the filesystem read-only") flagSet.BoolVar(&args.ro, "ro", false, "Mount the filesystem read-only")
flagSet.BoolVar(&args.kernel_cache, "kernel_cache", false, "Enable the FUSE kernel_cache option") flagSet.BoolVar(&args.kernel_cache, "kernel_cache", false, "Enable the FUSE kernel_cache option")
flagSet.BoolVar(&args.acl, "acl", false, "Enforce ACLs")
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key") flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file") flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")

View File

@ -396,6 +396,9 @@ func initGoFuse(rootNode fs.InodeEmbedder, args *argContainer) *fuse.Server {
// Make the kernel check the file permissions for us // Make the kernel check the file permissions for us
mOpts.Options = append(mOpts.Options, "default_permissions") mOpts.Options = append(mOpts.Options, "default_permissions")
} }
if args.acl {
mOpts.EnableAcl = true
}
if args.forcedecode { if args.forcedecode {
tlog.Info.Printf(tlog.ColorYellow + "THE OPTION \"-forcedecode\" IS ACTIVE. GOCRYPTFS WILL RETURN CORRUPT DATA!" + tlog.Info.Printf(tlog.ColorYellow + "THE OPTION \"-forcedecode\" IS ACTIVE. GOCRYPTFS WILL RETURN CORRUPT DATA!" +
tlog.ColorReset) tlog.ColorReset)

View File

@ -137,6 +137,7 @@ func writeTillFull(t *testing.T, path string) (int, syscall.Errno) {
return sz, 0 return sz, 0
} }
// TestDiskFull needs root permissions because it creates a loop disk
func TestDiskFull(t *testing.T) { func TestDiskFull(t *testing.T) {
if os.Getuid() != 0 { if os.Getuid() != 0 {
t.Skip("must run as root") t.Skip("must run as root")
@ -229,3 +230,84 @@ func TestDiskFull(t *testing.T) {
t.Fail() t.Fail()
} }
} }
func TestAcl(t *testing.T) {
if os.Getuid() != 0 {
t.Skip("must run as root")
}
cDir := test_helpers.InitFS(t)
os.Chmod(cDir, 0755)
pDir := cDir + ".mnt"
test_helpers.MountOrFatal(t, cDir, pDir, "-allow_other", "-acl", "-extpass=echo test")
defer test_helpers.UnmountPanic(pDir)
f1 := pDir + "/f1"
if err := ioutil.WriteFile(f1, []byte("hello world\n"), 000); err != nil {
t.Fatal(err)
}
openUser1234 := func(rwMode int) error {
return asUser(1234, 1234, nil, func() error {
fd, err := syscall.Open(f1, rwMode, 0)
if err != nil {
return err
}
defer syscall.Close(fd)
buf := make([]byte, 100)
if rwMode == syscall.O_RDONLY || rwMode == syscall.O_RDWR {
_, err = syscall.Read(fd, buf)
if err != nil {
return err
}
}
if rwMode == syscall.O_WRONLY || rwMode == syscall.O_RDWR {
_, err = syscall.Write(fd, buf)
if err != nil {
return err
}
}
return err
})
}
dumpAcl := func() {
out, err := exec.Command("getfacl", f1).CombinedOutput()
if err != nil {
t.Fatal(err)
}
t.Log(string(out))
}
if err := openUser1234(syscall.O_RDONLY); err == nil {
t.Error("this should have failed")
dumpAcl()
}
// Allow read
out, err := exec.Command("setfacl", "-m", "u:1234:r", f1).CombinedOutput()
if err != nil {
t.Fatal(string(out))
}
if err := openUser1234(syscall.O_RDONLY); err != nil {
t.Errorf("O_RDONLY should have worked, but got error: %v", err)
dumpAcl()
}
if err := openUser1234(syscall.O_WRONLY); err == nil {
t.Error("O_WRONLY should have failed")
dumpAcl()
}
// Allow write
out, err = exec.Command("setfacl", "-m", "u:1234:w", f1).CombinedOutput()
if err != nil {
t.Fatal(string(out))
}
if err := openUser1234(syscall.O_WRONLY); err != nil {
t.Errorf("O_WRONLY should have worked, but got error: %v", err)
dumpAcl()
}
if err := openUser1234(syscall.O_RDONLY); err == nil {
t.Error("O_RDONLY should have failed")
dumpAcl()
}
}