aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-12-26 08:08:41 +0900
committerOphestra <cat@gensokyo.uk>2025-12-26 08:08:41 +0900
commit0e476c5e5b5f5b5fccfab0794936e3ede1c8116a (patch)
tree6888d613595229085b15f9c57a1a8853270d2b42 /cmd
parent54712e04265f1e74194fe8df0cc8f596af2e80d5 (diff)
cmd/sharefs: allocate sharefs_private early
This also removes global state used by sharefs_init. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/sharefs/fuse-operations.h6
-rw-r--r--cmd/sharefs/fuse.go63
2 files changed, 40 insertions, 29 deletions
diff --git a/cmd/sharefs/fuse-operations.h b/cmd/sharefs/fuse-operations.h
index 34f388b3..9abc47ce 100644
--- a/cmd/sharefs/fuse-operations.h
+++ b/cmd/sharefs/fuse-operations.h
@@ -13,7 +13,11 @@
/* sharefs_private is populated by sharefs_init and contains process-wide context */
struct sharefs_private {
- int dirfd; /* source dirfd opened during sharefs_init */
+ 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);
diff --git a/cmd/sharefs/fuse.go b/cmd/sharefs/fuse.go
index 1a17f800..945650bd 100644
--- a/cmd/sharefs/fuse.go
+++ b/cmd/sharefs/fuse.go
@@ -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)