cmd/sharefs: create directory as root
All checks were successful
Test / Create distribution (push) Successful in 42s
Test / Sandbox (push) Successful in 2m20s
Test / Hakurei (push) Successful in 3m30s
Test / Sandbox (race detector) (push) Successful in 4m42s
Test / Flake checks (push) Successful in 1m36s
Test / ShareFS (push) Successful in 3m26s
Test / Hpkg (push) Successful in 4m19s
Test / Hakurei (race detector) (push) Successful in 5m30s

This optional behaviour is required on NixOS as it is otherwise impossible to set this up: systemd.mounts breaks startup order somehow even though my unit looks identical to generated ones, fileSystems does not support any kind of initialisation or ordering other than against other mount points.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-12-27 22:09:55 +09:00
parent ef1ebf12d9
commit e7982b4ee9
3 changed files with 36 additions and 5 deletions

View File

@@ -53,6 +53,9 @@ type (
// Whether sharefs_init failed. // Whether sharefs_init failed.
initFailed bool initFailed bool
// Whether to create source directory as root.
mkdir bool
// Open file descriptor to fuse. // Open file descriptor to fuse.
Fuse int Fuse int
@@ -157,6 +160,9 @@ func parseOpts(args *fuseArgs, setup *setupState, log *log.Logger) (ok bool) {
// Pathname to writable source directory. // Pathname to writable source directory.
source *C.char source *C.char
// Whether to create source directory as root.
mkdir C.int
// Decimal string representation of uid to set when running as root. // Decimal string representation of uid to set when running as root.
setuid *C.char setuid *C.char
// Decimal string representation of gid to set when running as root. // Decimal string representation of gid to set when running as root.
@@ -169,6 +175,7 @@ func parseOpts(args *fuseArgs, setup *setupState, log *log.Logger) (ok bool) {
if C.fuse_opt_parse(args, unsafe.Pointer(&unsafeOpts), &[]C.struct_fuse_opt{ if C.fuse_opt_parse(args, unsafe.Pointer(&unsafeOpts), &[]C.struct_fuse_opt{
{templ: C.CString("source=%s"), offset: C.ulong(unsafe.Offsetof(unsafeOpts.source)), value: 0}, {templ: C.CString("source=%s"), offset: C.ulong(unsafe.Offsetof(unsafeOpts.source)), value: 0},
{templ: C.CString("mkdir"), offset: C.ulong(unsafe.Offsetof(unsafeOpts.mkdir)), value: 1},
{templ: C.CString("setuid=%s"), offset: C.ulong(unsafe.Offsetof(unsafeOpts.setuid)), value: 0}, {templ: C.CString("setuid=%s"), offset: C.ulong(unsafe.Offsetof(unsafeOpts.setuid)), value: 0},
{templ: C.CString("setgid=%s"), offset: C.ulong(unsafe.Offsetof(unsafeOpts.setgid)), value: 0}, {templ: C.CString("setgid=%s"), offset: C.ulong(unsafe.Offsetof(unsafeOpts.setgid)), value: 0},
@@ -223,6 +230,7 @@ func parseOpts(args *fuseArgs, setup *setupState, log *log.Logger) (ok bool) {
} else { } else {
setup.Source = a setup.Source = a
} }
setup.mkdir = unsafeOpts.mkdir != 0
if unsafeOpts.setuid == nil { if unsafeOpts.setuid == nil {
setup.Setuid = -1 setup.Setuid = -1
@@ -339,6 +347,9 @@ func _main(s ...string) (exitCode int) {
} else if setup.Fuse < 3 && (setup.Setuid > 0 || setup.Setgid > 0) { } else if setup.Fuse < 3 && (setup.Setuid > 0 || setup.Setgid > 0) {
log.Println("setuid and setgid has no effect when not starting as root") log.Println("setuid and setgid has no effect when not starting as root")
return 1 return 1
} else if setup.mkdir {
log.Println("mkdir has no effect when not starting as root")
return 1
} }
op := C.struct_fuse_operations{ op := C.struct_fuse_operations{
@@ -387,6 +398,20 @@ func _main(s ...string) (exitCode int) {
log.Println("setuid and setgid must not be 0") log.Println("setuid and setgid must not be 0")
return 5 return 5
} }
if setup.mkdir {
if err := os.MkdirAll(setup.Source.String(), 0700); err != nil {
if !errors.Is(err, os.ErrExist) {
log.Println(err)
return 5
}
// skip setup for existing source directory
} else if err = os.Chown(setup.Source.String(), setup.Setuid, setup.Setgid); err != nil {
log.Println(err)
return 5
}
}
if err := syscall.Setresgid(setup.Setgid, setup.Setgid, setup.Setgid); err != nil { if err := syscall.Setresgid(setup.Setgid, setup.Setgid, setup.Setgid); err != nil {
log.Printf("cannot set gid: %v", err) log.Printf("cannot set gid: %v", err)
return 5 return 5

View File

@@ -27,6 +27,7 @@ check_bad_opts_output("setgid=-1", "sharefs: invalid value for option setgid\n")
check_bad_opts_output("setuid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") check_bad_opts_output("setuid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n")
check_bad_opts_output("setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") check_bad_opts_output("setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n")
check_bad_opts_output("setuid=1023,setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") check_bad_opts_output("setuid=1023,setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n")
check_bad_opts_output("mkdir", "sharefs: mkdir has no effect when not starting as root\n")
# Starting as root without setuid/setgid: # Starting as root without setuid/setgid:
check_bad_opts_output("allow_other", "sharefs: setuid and setgid must not be 0\n", privileged=True) check_bad_opts_output("allow_other", "sharefs: setuid and setgid must not be 0\n", privileged=True)
@@ -37,6 +38,14 @@ check_bad_opts_output("setgid=1023", "sharefs: setuid and setgid must not be 0\n
machine.fail("umount /mnt") machine.fail("umount /mnt")
machine.succeed("rmdir /mnt") machine.succeed("rmdir /mnt")
# Unprivileged mount/unmount:
machine.succeed("sudo -u alice -i mkdir /home/alice/{sdcard,persistent}")
machine.succeed("sudo -u alice -i /etc/sharefs -o source=/home/alice/persistent /home/alice/sdcard")
machine.succeed("sudo -u alice -i touch /home/alice/sdcard/check")
machine.succeed("sudo -u alice -i umount /home/alice/sdcard")
machine.succeed("sudo -u alice -i rm /home/alice/persistent/check")
machine.succeed("sudo -u alice -i rmdir /home/alice/{sdcard,persistent}")
# Benchmark sharefs: # Benchmark sharefs:
machine.succeed("fs_mark -v -d /sdcard/fs_mark -l /tmp/fs_log.txt") machine.succeed("fs_mark -v -d /sdcard/fs_mark -l /tmp/fs_log.txt")
machine.copy_from_vm("/tmp/fs_log.txt", "") machine.copy_from_vm("/tmp/fs_log.txt", "")

View File

@@ -73,11 +73,7 @@ in
NoNewPrivileges = true; NoNewPrivileges = true;
}; };
script = '' script = ''
${pkgs.coreutils}/bin/install \ ${pkgs.coreutils}/bin/install -dm0 ${cfg.sharefs.name}
-dm0700 \
-o ${cfg.sharefs.user} \
-g ${cfg.sharefs.group} \
${cfg.sharefs.source} ${cfg.sharefs.name}
exec ${cfg.package}/libexec/sharefs -f \ exec ${cfg.package}/libexec/sharefs -f \
-o ${ -o ${
@@ -91,6 +87,7 @@ in
"setuid=$(id -u ${cfg.sharefs.user})" "setuid=$(id -u ${cfg.sharefs.user})"
"setgid=$(id -g ${cfg.sharefs.group})" "setgid=$(id -g ${cfg.sharefs.group})"
"source=${cfg.sharefs.source}" "source=${cfg.sharefs.source}"
"mkdir"
] ]
} ${cfg.sharefs.name} } ${cfg.sharefs.name}
''; '';