mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-29 15:59:10 +01:00
[client] Drop SSH privileges through libc in PKCS#11 package builds (#8323)
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
//go:build pkcs11 && linux && !android && (amd64 || arm64)
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
// This build links libc through purego, whose fakecgo runtime marks the binary as cgo
|
||||
// without registering the libc hooks a real cgo build provides. syscall's setuid family
|
||||
// then panics in AllThreadsSyscall, so the calls go to libc directly: glibc applies them
|
||||
// to every thread, and all Go threads here are created through pthread_create.
|
||||
|
||||
type libcSetID struct {
|
||||
setgroups func(size uintptr, list *uint32) int32
|
||||
setgid func(gid uint32) int32
|
||||
setuid func(uid uint32) int32
|
||||
setegid func(egid uint32) int32
|
||||
seteuid func(euid uint32) int32
|
||||
errnoLocation func() *int32
|
||||
}
|
||||
|
||||
var (
|
||||
libcSetIDOnce sync.Once
|
||||
libcSetIDFns libcSetID
|
||||
libcSetIDErr error
|
||||
)
|
||||
|
||||
func loadLibcSetID() (*libcSetID, error) {
|
||||
libcSetIDOnce.Do(func() {
|
||||
syms := []struct {
|
||||
fn any
|
||||
name string
|
||||
}{
|
||||
{&libcSetIDFns.setgroups, "setgroups"},
|
||||
{&libcSetIDFns.setgid, "setgid"},
|
||||
{&libcSetIDFns.setuid, "setuid"},
|
||||
{&libcSetIDFns.setegid, "setegid"},
|
||||
{&libcSetIDFns.seteuid, "seteuid"},
|
||||
{&libcSetIDFns.errnoLocation, "__errno_location"},
|
||||
}
|
||||
for _, s := range syms {
|
||||
addr, err := purego.Dlsym(purego.RTLD_DEFAULT, s.name)
|
||||
if err != nil {
|
||||
libcSetIDErr = fmt.Errorf("resolve libc %s: %w", s.name, err)
|
||||
return
|
||||
}
|
||||
purego.RegisterFunc(s.fn, addr)
|
||||
}
|
||||
})
|
||||
if libcSetIDErr != nil {
|
||||
return nil, libcSetIDErr
|
||||
}
|
||||
return &libcSetIDFns, nil
|
||||
}
|
||||
|
||||
// libcCall runs call on a locked thread so errno is read from the thread that set it.
|
||||
func libcCall(call func(*libcSetID) int32) error {
|
||||
fns, err := loadLibcSetID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if call(fns) == 0 {
|
||||
return nil
|
||||
}
|
||||
if errno := *fns.errnoLocation(); errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
return syscall.EINVAL
|
||||
}
|
||||
|
||||
func setgroups(gids []int) error {
|
||||
list := make([]uint32, len(gids))
|
||||
for i, g := range gids {
|
||||
list[i] = uint32(g)
|
||||
}
|
||||
return libcCall(func(f *libcSetID) int32 {
|
||||
if len(list) == 0 {
|
||||
return f.setgroups(0, nil)
|
||||
}
|
||||
return f.setgroups(uintptr(len(list)), &list[0])
|
||||
})
|
||||
}
|
||||
|
||||
func setgid(gid int) error {
|
||||
return libcCall(func(f *libcSetID) int32 { return f.setgid(uint32(gid)) })
|
||||
}
|
||||
|
||||
func setuid(uid int) error {
|
||||
return libcCall(func(f *libcSetID) int32 { return f.setuid(uint32(uid)) })
|
||||
}
|
||||
|
||||
func setegid(egid int) error {
|
||||
return libcCall(func(f *libcSetID) int32 { return f.setegid(uint32(egid)) })
|
||||
}
|
||||
|
||||
func seteuid(euid int) error {
|
||||
return libcCall(func(f *libcSetID) int32 { return f.seteuid(uint32(euid)) })
|
||||
}
|
||||
Reference in New Issue
Block a user