cmd/sharefs: allocate sharefs_private early
All checks were successful
Test / Create distribution (push) Successful in 43s
Test / Sandbox (push) Successful in 2m21s
Test / ShareFS (push) Successful in 3m26s
Test / Hpkg (push) Successful in 4m14s
Test / Sandbox (race detector) (push) Successful in 4m31s
Test / Hakurei (race detector) (push) Successful in 5m31s
Test / Hakurei (push) Successful in 2m34s
Test / Flake checks (push) Successful in 1m39s
All checks were successful
Test / Create distribution (push) Successful in 43s
Test / Sandbox (push) Successful in 2m21s
Test / ShareFS (push) Successful in 3m26s
Test / Hpkg (push) Successful in 4m14s
Test / Sandbox (race detector) (push) Successful in 4m31s
Test / Hakurei (race detector) (push) Successful in 5m31s
Test / Hakurei (push) Successful in 2m34s
Test / Flake checks (push) Successful in 1m39s
This also removes global state used by sharefs_init. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -14,6 +14,10 @@
|
||||
/* sharefs_private is populated by sharefs_init and contains process-wide context */
|
||||
struct sharefs_private {
|
||||
int dirfd; /* source dirfd opened during sharefs_init */
|
||||
bool init_failed; /* whether sharefs_init failed */
|
||||
uintptr_t source_handle; /* cgo handle of pathname to open for dirfd, freed during sharefs_init */
|
||||
uintptr_t setuid; /* uid to set by sharefs_init when running as root */
|
||||
uintptr_t setgid; /* gid to set by sharefs_init when running as root */
|
||||
};
|
||||
|
||||
int sharefs_getattr(const char *pathname, struct stat *statbuf, struct fuse_file_info *fi);
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/cgo"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
@@ -33,27 +35,19 @@ type (
|
||||
fuseArgs = C.struct_fuse_args
|
||||
)
|
||||
|
||||
var (
|
||||
// initFailed is set to true by sharefs_init if initialisation was unsuccessful.
|
||||
initFailed bool
|
||||
|
||||
// initSource is pathname to the writable source directory used by sharefs_init to populate sharefs_private.
|
||||
initSource string
|
||||
// initSetUidGid is the uid and gid to set by sharefs_init when running as root.
|
||||
initSetUidGid [2]int
|
||||
)
|
||||
|
||||
//export sharefs_init
|
||||
func sharefs_init(_ *C.struct_fuse_conn_info, cfg *C.struct_fuse_config) unsafe.Pointer {
|
||||
private_data := C.malloc(C.size_t(unsafe.Sizeof(C.struct_sharefs_private{})))
|
||||
priv := (*C.struct_sharefs_private)(private_data)
|
||||
ctx := C.fuse_get_context()
|
||||
priv := (*C.struct_sharefs_private)(ctx.private_data)
|
||||
source := cgo.Handle(priv.source_handle).Value().(string)
|
||||
|
||||
setuid, setgid := int(priv.setuid), int(priv.setgid)
|
||||
if os.Geteuid() == 0 {
|
||||
if initSetUidGid[0] <= 0 || initSetUidGid[1] <= 0 {
|
||||
if setuid <= 0 || setgid <= 0 {
|
||||
log.Println("setuid and setgid must not be 0")
|
||||
goto fail
|
||||
}
|
||||
if err := syscall.Setresgid(initSetUidGid[1], initSetUidGid[1], initSetUidGid[1]); err != nil {
|
||||
if err := syscall.Setresgid(setgid, setgid, setgid); err != nil {
|
||||
log.Printf("cannot set gid: %v", err)
|
||||
goto fail
|
||||
}
|
||||
@@ -61,7 +55,7 @@ func sharefs_init(_ *C.struct_fuse_conn_info, cfg *C.struct_fuse_config) unsafe.
|
||||
log.Printf("cannot set supplementary groups: %v", err)
|
||||
goto fail
|
||||
}
|
||||
if err := syscall.Setresuid(initSetUidGid[0], initSetUidGid[0], initSetUidGid[0]); err != nil {
|
||||
if err := syscall.Setresuid(setuid, setuid, setuid); err != nil {
|
||||
log.Printf("cannot set uid: %v", err)
|
||||
goto fail
|
||||
}
|
||||
@@ -75,30 +69,37 @@ func sharefs_init(_ *C.struct_fuse_conn_info, cfg *C.struct_fuse_config) unsafe.
|
||||
cfg.negative_timeout = 0
|
||||
|
||||
// all future filesystem operations happen through this dirfd
|
||||
if fd, err := syscall.Open(initSource, syscall.O_DIRECTORY|syscall.O_RDONLY, 0); err != nil {
|
||||
log.Printf("cannot open %q: %v", initSource, err)
|
||||
if fd, err := syscall.Open(source, syscall.O_DIRECTORY|syscall.O_RDONLY, 0); err != nil {
|
||||
log.Printf("cannot open %q: %v", source, err)
|
||||
goto fail
|
||||
} else if err = syscall.Fchdir(fd); err != nil {
|
||||
log.Printf("cannot enter %q: %s", initSource, err)
|
||||
log.Printf("cannot enter %q: %s", source, err)
|
||||
goto fail
|
||||
} else {
|
||||
priv.dirfd = C.int(fd)
|
||||
}
|
||||
|
||||
return private_data
|
||||
return ctx.private_data
|
||||
|
||||
fail:
|
||||
C.free(private_data)
|
||||
C.fuse_exit(C.fuse_get_context().fuse)
|
||||
initFailed = true
|
||||
sourceHandle := cgo.Handle(priv.source_handle)
|
||||
priv.source_handle = 0
|
||||
sourceHandle.Delete()
|
||||
priv.init_failed = true
|
||||
|
||||
C.fuse_exit(ctx.fuse)
|
||||
return nil
|
||||
}
|
||||
|
||||
//export sharefs_destroy
|
||||
func sharefs_destroy(private_data unsafe.Pointer) {
|
||||
if private_data != nil {
|
||||
defer C.free(private_data)
|
||||
priv := (*C.struct_sharefs_private)(private_data)
|
||||
if priv.source_handle != 0 {
|
||||
sourceHandle := cgo.Handle(priv.source_handle)
|
||||
priv.source_handle = 0
|
||||
sourceHandle.Delete()
|
||||
}
|
||||
|
||||
if err := syscall.Close(int(priv.dirfd)); err != nil {
|
||||
log.Printf("cannot close source directory: %v", err)
|
||||
@@ -153,7 +154,7 @@ func parseOpts(args *C.struct_fuse_args) (
|
||||
defer C.free(unsafe.Pointer(unsafeOpts.setgid))
|
||||
}
|
||||
|
||||
if unsafeOpts.source == nil {
|
||||
if unsafeOpts.source == nil || *unsafeOpts.source == 0 {
|
||||
showHelp()
|
||||
ret = 1
|
||||
return
|
||||
@@ -205,12 +206,18 @@ func _main(argc int, argv **C.char) int {
|
||||
// don't mask creation mode, kernel already did that
|
||||
syscall.Umask(0)
|
||||
|
||||
var pinner runtime.Pinner
|
||||
defer pinner.Unpin()
|
||||
|
||||
args := C.struct_fuse_args{argc: C.int(argc), argv: argv, allocated: 1}
|
||||
|
||||
// this causes the kernel to enforce access control based on
|
||||
// struct stat populated by sharefs_getattr
|
||||
unsafeAddArgument(&args, "-odefault_permissions\x00")
|
||||
|
||||
var priv C.struct_sharefs_private
|
||||
pinner.Pin(&priv)
|
||||
|
||||
{
|
||||
source, setuid, setgid, ret := parseOpts(&args)
|
||||
if ret != 0 {
|
||||
@@ -221,7 +228,7 @@ func _main(argc int, argv **C.char) int {
|
||||
log.Println(err)
|
||||
return 1
|
||||
} else {
|
||||
initSource = a
|
||||
priv.source_handle = C.uintptr_t(cgo.NewHandle(a))
|
||||
}
|
||||
|
||||
if os.Geteuid() == 0 {
|
||||
@@ -233,7 +240,7 @@ func _main(argc int, argv **C.char) int {
|
||||
log.Println("setuid and setgid has no effect when not starting as root")
|
||||
return 1
|
||||
}
|
||||
initSetUidGid[0], initSetUidGid[1] = setuid, setgid
|
||||
priv.setuid, priv.setgid = C.uintptr_t(setuid), C.uintptr_t(setgid)
|
||||
}
|
||||
|
||||
// TODO(ophestra): spawn container here, set PR_SET_NO_NEW_PRIVS and enforce landlock
|
||||
@@ -257,9 +264,9 @@ func _main(argc int, argv **C.char) int {
|
||||
statfs: closure(C.sharefs_statfs),
|
||||
release: closure(C.sharefs_release),
|
||||
fsync: closure(C.sharefs_fsync),
|
||||
}, nil)
|
||||
}, unsafe.Pointer(&priv))
|
||||
|
||||
if initFailed {
|
||||
if priv.init_failed {
|
||||
return 1
|
||||
} else {
|
||||
return int(fuse_main_return)
|
||||
|
||||
Reference in New Issue
Block a user