Exemple #1
0
func getUnitFileName() (unit string, err error) {
	libname := C.CString("libsystemd.so")
	defer C.free(unsafe.Pointer(libname))
	handle := C.dlopen(libname, C.RTLD_LAZY)
	if handle == nil {
		err = fmt.Errorf("error opening libsystemd.so")
		return
	}
	defer func() {
		if r := C.dlclose(handle); r != 0 {
			err = fmt.Errorf("error closing libsystemd.so")
		}
	}()

	sym := C.CString("sd_pid_get_unit")
	defer C.free(unsafe.Pointer(sym))
	sd_pid_get_unit := C.dlsym(handle, sym)
	if sd_pid_get_unit == nil {
		err = fmt.Errorf("error resolving sd_pid_get_unit function")
		return
	}

	var s string
	u := C.CString(s)
	defer C.free(unsafe.Pointer(u))

	ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
	if ret < 0 {
		err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
		return
	}

	unit = C.GoString(u)
	return
}
Exemple #2
0
// populateFunctions ranges over the library's ftable, initializing each
// function inside. Assumes that the caller executes runtime.LockOSThread.
func (lib *Lib) populateFunctions() error {
	libT := reflect.TypeOf(lib.ftable)
	functionsV := reflect.ValueOf(lib).Elem().FieldByName("ftable")

	n := libT.NumField()
	for i := 0; i < n; i++ {
		// Get the field name, and make sure it's an Fp_.
		f := libT.FieldByIndex([]int{i})

		if !strings.HasPrefix(f.Name, fpPrefix) {
			return fmt.Errorf(
				"Unexpected: field %q does not start with %q",
				f.Name, fpPrefix)
		}

		// Resolve the symbol.
		cfname := C.CString(f.Name[len(fpPrefix):])
		v := C.dlsym(lib.handle, cfname)
		C.free(unsafe.Pointer(cfname))
		if v == nil {
			return fmt.Errorf("%s", C.GoString(C.dlerror()))
		}

		// Save the value into the struct
		functionsV.FieldByIndex([]int{i}).SetPointer(v)
	}

	return nil
}
Exemple #3
0
func getSlice() (slice string, err error) {
	libname := C.CString("libsystemd.so")
	defer C.free(unsafe.Pointer(libname))
	handle := C.dlopen(libname, C.RTLD_LAZY)
	if handle == nil {
		err = fmt.Errorf("error opening libsystemd.so")
		return
	}
	defer func() {
		if r := C.dlclose(handle); r != 0 {
			err = fmt.Errorf("error closing libsystemd.so")
		}
	}()

	sym := C.CString("sd_pid_get_slice")
	defer C.free(unsafe.Pointer(sym))
	sd_pid_get_slice := C.dlsym(handle, sym)
	if sd_pid_get_slice == nil {
		err = fmt.Errorf("error resolving sd_pid_get_slice function")
		return
	}

	var s string
	sl := C.CString(s)
	defer C.free(unsafe.Pointer(sl))

	ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
	if ret < 0 {
		err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
		return
	}

	slice = C.GoString(sl)
	return
}
Exemple #4
0
// GetRunningSlice attempts to retrieve the name of the systemd slice in which
// the current process is running.
// This function is a wrapper around the libsystemd C library; if it cannot be
// opened, an error is returned.
func GetRunningSlice() (slice string, err error) {
	var h *libHandle
	h, err = getHandle()
	if err != nil {
		return
	}
	defer func() {
		if err1 := h.Close(); err1 != nil {
			err = err1
		}
	}()

	sym := C.CString("sd_pid_get_slice")
	defer C.free(unsafe.Pointer(sym))
	sd_pid_get_slice := C.dlsym(h.handle, sym)
	if sd_pid_get_slice == nil {
		err = fmt.Errorf("error resolving sd_pid_get_slice function")
		return
	}

	var s string
	sl := C.CString(s)
	defer C.free(unsafe.Pointer(sl))

	ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
	if ret < 0 {
		err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
		return
	}

	return C.GoString(sl), nil
}
Exemple #5
0
// CurrentUnitName attempts to retrieve the name of the systemd system unit
// from which the calling process has been invoked. It wraps the systemd
// `sd_pid_get_unit` call, with the same caveat: for processes not part of a
// systemd system unit, this function will return an error.
func CurrentUnitName() (unit string, err error) {
	var h *libHandle
	h, err = getHandle()
	if err != nil {
		return
	}
	defer func() {
		if err1 := h.Close(); err1 != nil {
			err = err1
		}
	}()

	sym := C.CString("sd_pid_get_unit")
	defer C.free(unsafe.Pointer(sym))
	sd_pid_get_unit := C.dlsym(h.handle, sym)
	if sd_pid_get_unit == nil {
		err = fmt.Errorf("error resolving sd_pid_get_unit function")
		return
	}

	var s string
	u := C.CString(s)
	defer C.free(unsafe.Pointer(u))

	ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
	if ret < 0 {
		err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
		return
	}

	unit = C.GoString(u)
	return
}
Exemple #6
0
func FindProc(lib string, handle unsafe.Pointer, n string) (addr uintptr, e error) {
	cn := C.CString(n) //TODO(t): use bytePtrFromString()?
	defer C.free(unsafe.Pointer(cn))
	addr = uintptr(C.dlsym(handle, cn))
	if addr == 0 {
		e = errors.New(n + " not found in " + lib)
	}
	return
}
Exemple #7
0
func Sym(handle uintptr, symbol string) (uintptr, error) {
	ptr := C.CString(symbol)
	defer C.free(unsafe.Pointer(ptr))
	ret := C.dlsym(unsafe.Pointer(handle), ptr)
	if ret != nil {
		return uintptr(ret), nil
	}
	return uintptr(ret), errors.New(C.GoString(C.dlerror()))
}
Exemple #8
0
func MustFindProc(lib string, handle unsafe.Pointer, n string) (addr uintptr) {
	cn := C.CString(n) //TODO(t): use bytePtrFromString()?
	defer C.free(unsafe.Pointer(cn))
	addr = uintptr(C.dlsym(handle, cn))
	if addr == 0 {
		panic("mustFindProc of " + n + " in " + lib + " failed")
	}
	return
}
Exemple #9
0
func fn(fname string) unsafe.Pointer {
	name := C.CString(fname)
	defer C.free(unsafe.Pointer(name))

	p := C.dlsym(alHandle, name)
	if uintptr(p) == 0 {
		log.Fatalf("al: couldn't dlsym %q", fname)
	}
	return p
}
Exemple #10
0
func (h Handle) Symbol(symbol string) (uintptr, error) {
	c_sym := C.CString(symbol)
	defer C.free(unsafe.Pointer(c_sym))

	c_addr := C.dlsym(h.c, c_sym)
	if c_addr == nil {
		c_err := C.dlerror()
		return 0, fmt.Errorf("dl: %s", C.GoString(c_err))
	}
	return uintptr(c_addr), nil
}
Exemple #11
0
func Symbol(handle uintptr, symbol string) (uintptr, error) {
	cstr := C.CString(symbol)
	defer C.free(unsafe.Pointer(cstr))

	sym := C.dlsym(unsafe.Pointer(handle), cstr)
	if sym == nil {
		return 0, dlerror("dlsym")
	}

	return uintptr(sym), nil
}
Exemple #12
0
// GetSymbolPointer takes a symbol name and returns a pointer to the symbol.
func (l *LibHandle) GetSymbolPointer(symbol string) (unsafe.Pointer, error) {
	sym := C.CString(symbol)
	defer C.free(unsafe.Pointer(sym))

	C.dlerror()
	p := C.dlsym(l.Handle, sym)
	e := C.dlerror()
	if e != nil {
		return nil, fmt.Errorf("error resolving symbol %q: %v", symbol, errors.New(C.GoString(e)))
	}

	return p, nil
}
Exemple #13
0
func getSymbolPointer(handle unsafe.Pointer, symbol string) (unsafe.Pointer, error) {
	sym := C.CString(symbol)
	defer C.free(unsafe.Pointer(sym))

	C.dlerror()
	p := C.dlsym(handle, sym)
	e := C.dlerror()
	if e != nil {
		return nil, errwrap.Wrap(fmt.Errorf("error resolving symbol %q", symbol), errors.New(C.GoString(e)))
	}

	return p, nil
}
Exemple #14
0
func dlsym(lib unsafe.Pointer, name string) (addr unsafe.Pointer, err error) {
	var s = C.CString(name)
	defer C.free(unsafe.Pointer(s))

	dlmtx.Lock()
	defer dlmtx.Unlock()

	if addr = C.dlsym(lib, s); addr == nil {
		err = dlerror()
	}

	return
}
Exemple #15
0
func loadThySelf(t *testing.T, symbol string) {
	this_process := C.dlopen(nil, C.RTLD_NOW)
	if this_process == nil {
		t.Fatal("dlopen:", C.GoString(C.dlerror()))
	}
	defer C.dlclose(this_process)

	symbol_address := C.dlsym(this_process, C.CString(symbol))
	if symbol_address == nil {
		t.Fatal("dlsym:", C.GoString(C.dlerror()))
	} else {
		t.Log(symbol, symbol_address)
	}
}
Exemple #16
0
func (library *Library) Sym(name string) *Function {
	if library == nil {
		return nil
	}
	if library.ptr == nil {
		return nil
	}
	function := &Function{}
	function.name = name
	cname := cstr(function.name)
	defer cname.free()
	function.ptr = C.dlsym(library.ptr, cname)
	return function
}
Exemple #17
0
/*
* loadThySelf()
* Go doesn't support dynamic linking. However, it supports a C interface that supports
* dynamic linking. And it supports symbol export allowing callbacks into go functions
* using a C calling convention. So, Go supports dynamic linking.
 */
func loadThySelf(symbol string) *[0]byte {

	this_process := C.dlopen(nil, C.RTLD_NOW)
	if this_process == nil {
		panic(C.GoString(C.dlerror()))
	}

	symbol_address := C.dlsym(this_process, C.CString(symbol))
	if symbol_address == nil {
		panic(C.GoString(C.dlerror()))
	}

	C.dlclose(this_process)
	return (*[0]byte)(unsafe.Pointer(symbol_address))
}
Exemple #18
0
func loadThySelf(t *testing.T, symbol string) {
	this_process := C.dlopen(nil, C.RTLD_NOW)
	if this_process == nil {
		t.Error("dlopen:", C.GoString(C.dlerror()))
		return
	}
	defer C.dlclose(this_process)

	symbol_address := C.dlsym(this_process, C.CString(symbol))
	if symbol_address == nil {
		t.Error("dlsym:", C.GoString(C.dlerror()))
		return
	}
	t.Log(symbol, symbol_address)
	C.call4029(symbol_address)
}
Exemple #19
0
// RunningFromSystemService tries to detect whether the current process has
// been invoked from a system service. The condition for this is whether the
// process is _not_ a user process. User processes are those running in session
// scopes or under per-user `systemd --user` instances.
//
// To avoid false positives on systems without `pam_systemd` (which is
// responsible for creating user sessions), this function also uses a heuristic
// to detect whether it's being invoked from a session leader process. This is
// the case if the current process is executed directly from a service file
// (e.g. with `ExecStart=/this/cmd`). Note that this heuristic will fail if the
// command is instead launched in a subshell or similar so that it is not
// session leader (e.g. `ExecStart=/bin/bash -c "/this/cmd"`)
//
// This function is a wrapper around the libsystemd C library; if this is
// unable to successfully open a handle to the library for any reason (e.g. it
// cannot be found), an errr will be returned
func RunningFromSystemService() (ret bool, err error) {
	var h *libHandle
	h, err = getHandle()
	if err != nil {
		return
	}
	defer func() {
		if err1 := h.Close(); err1 != nil {
			err = err1
		}
	}()

	sym := C.CString("sd_pid_get_owner_uid")
	defer C.free(unsafe.Pointer(sym))
	sd_pid_get_owner_uid := C.dlsym(h.handle, sym)
	if sd_pid_get_owner_uid == nil {
		err = fmt.Errorf("error resolving sd_pid_get_owner_uid function")
		return
	}

	var uid C.uid_t
	errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
	serrno := syscall.Errno(-errno)
	// when we're running from a unit file, sd_pid_get_owner_uid returns
	// ENOENT (systemd <220) or ENXIO (systemd >=220)
	switch {
	case errno >= 0:
		ret = false
	case serrno == syscall.ENOENT, serrno == syscall.ENXIO:
		// Since the implementation of sessions in systemd relies on
		// the `pam_systemd` module, using the sd_pid_get_owner_uid
		// heuristic alone can result in false positives if that module
		// (or PAM itself) is not present or properly configured on the
		// system. As such, we also check if we're the session leader,
		// which should be the case if we're invoked from a unit file,
		// but not if e.g. we're invoked from the command line from a
		// user's login session
		ret = C.am_session_leader() == 1
	default:
		err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
	}
	return
}
Exemple #20
0
func dlsym(handle uintptr, symbol string) (uintptr, error) {
	Csymbol := C.CString(symbol)
	defer C.free(unsafe.Pointer(Csymbol))
	Chandle := unsafe.Pointer(handle)

	// First clean preview error
	_, _ = C.dlerror()

	// Then call dlsym
	CSymbolHandle, _ := C.dlsym(Chandle, Csymbol)

	// Test error now
	CErrString, _ := C.dlerror()

	if CErrString == nil {
		return uintptr(CSymbolHandle), nil
	} else {
		return 0, errors.New(C.GoString(CErrString))
	}
}
Exemple #21
0
func isRunningFromUnitFile() (ret bool, err error) {
	libname := C.CString("libsystemd.so")
	defer C.free(unsafe.Pointer(libname))
	handle := C.dlopen(libname, C.RTLD_LAZY)
	if handle == nil {
		// we can't open libsystemd.so so we assume systemd is not
		// installed and we're not running from a unit file
		ret = false
		return
	}
	defer func() {
		if r := C.dlclose(handle); r != 0 {
			err = fmt.Errorf("error closing libsystemd.so")
		}
	}()

	sd_pid_get_owner_uid := C.dlsym(handle, C.CString("sd_pid_get_owner_uid"))
	if sd_pid_get_owner_uid == nil {
		err = fmt.Errorf("error resolving sd_pid_get_owner_uid function")
		return
	}

	var uid C.uid_t
	errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
	// when we're running from a unit file, sd_pid_get_owner_uid returns
	// ENOENT (systemd <220) or ENXIO (systemd >=220)
	switch {
	case errno >= 0:
		ret = false
		return
	case syscall.Errno(-errno) == syscall.ENOENT || syscall.Errno(-errno) == syscall.ENXIO:
		ret = true
		return
	default:
		err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
		return
	}
}
Exemple #22
0
// Sym loads the symbol identified by the given name into
// the out parameter. Note that out must always be a pointer.
// See the package documentation to learn how types are mapped
// between Go and C.
func (d *DL) Sym(symbol string, out interface{}) error {
	s := C.CString(symbol)
	defer C.free(unsafe.Pointer(s))
	mu.Lock()
	handle := C.dlsym(d.handle, s)
	if handle == nil {
		err := dlerror()
		mu.Unlock()
		return err
	}
	mu.Unlock()
	if out == nil {
		return errors.New("out can't be nil")
	}
	switch val := out.(type) {
	case *int:
		// We treat Go's int as long, since it
		// varies depending on the platform bit size
		*val = *(*int)(handle)
	case *int8:
		*val = *(*int8)(handle)
	case *int16:
		*val = *(*int16)(handle)
	case *int32:
		*val = *(*int32)(handle)
	case *int64:
		*val = *(*int64)(handle)
	case *uint:
		// We treat Go's uint as unsigned long, since it
		// varies depending on the platform bit size
		*val = *(*uint)(handle)
	case *uint8:
		*val = *(*uint8)(handle)
	case *uint16:
		*val = *(*uint16)(handle)
	case *uint32:
		*val = *(*uint32)(handle)
	case *uint64:
		*val = *(*uint64)(handle)
	case *uintptr:
		*val = *(*uintptr)(handle)
	case *float32:
		*val = *(*float32)(handle)
	case *float64:
		*val = *(*float64)(handle)
	case *string:
		*val = C.GoString(*(**C.char)(handle))
	case *unsafe.Pointer:
		*val = handle
	default:
		ref := reflect.ValueOf(out)
		if !ref.IsValid() || ref.Kind() != reflect.Ptr {
			return fmt.Errorf("out must be a pointer, not %T", out)
		}
		elem := ref.Elem()
		switch elem.Kind() {
		case reflect.Func:
			typ := elem.Type()
			tr, err := makeTrampoline(typ, handle)
			if err != nil {
				return err
			}
			v := reflect.MakeFunc(typ, tr)
			elem.Set(v)
		case reflect.Ptr:
			v := reflect.NewAt(elem.Type().Elem(), handle)
			elem.Set(v)
		default:
			return fmt.Errorf("invalid out type %T", out)
		}
	}
	return nil
}
Exemple #23
0
// Sym loads the symbol identified by the given name into
// the out parameter. Note that out must always be a pointer.
// See the package documentation to learn how types are mapped
// between Go and C.
func (d *DL) Sym(symbol string, out interface{}) error {
	s := C.CString(symbol)
	defer C.free(unsafe.Pointer(s))
	mu.Lock()
	handle := C.dlsym(d.handle, s)
	if handle == nil {
		err := dlerror()
		mu.Unlock()
		return err
	}
	mu.Unlock()
	val := reflect.ValueOf(out)
	if !val.IsValid() || val.Kind() != reflect.Ptr {
		return fmt.Errorf("out must be a pointer, not %T", out)
	}
	if val.IsNil() {
		return errors.New("out can't be nil")
	}
	elem := val.Elem()
	typ := reflect.TypeOf(elem.Interface())
	switch typ.Kind() {
	case reflect.Int:
		// We treat Go's int as long, since it
		// varies depending on the platform bit size
		elem.SetInt(int64(*(*int)(handle)))
	case reflect.Int8:
		elem.SetInt(int64(*(*int8)(handle)))
	case reflect.Int16:
		elem.SetInt(int64(*(*int16)(handle)))
	case reflect.Int32:
		elem.SetInt(int64(*(*int32)(handle)))
	case reflect.Int64:
		elem.SetInt(int64(*(*int64)(handle)))
	case reflect.Uint:
		// We treat Go's uint as unsigned long, since it
		// varies depending on the platform bit size
		elem.SetUint(uint64(*(*uint)(handle)))
	case reflect.Uint8:
		elem.SetUint(uint64(*(*uint8)(handle)))
	case reflect.Uint16:
		elem.SetUint(uint64(*(*uint16)(handle)))
	case reflect.Uint32:
		elem.SetUint(uint64(*(*uint32)(handle)))
	case reflect.Uint64:
		elem.SetUint(uint64(*(*uint64)(handle)))
	case reflect.Uintptr:
		elem.SetUint(uint64(*(*uintptr)(handle)))
	case reflect.Float32:
		elem.SetFloat(float64(*(*float32)(handle)))
	case reflect.Float64:
		elem.SetFloat(float64(*(*float64)(handle)))
	case reflect.Func:
		tr, err := makeTrampoline(typ, handle)
		if err != nil {
			return err
		}
		v := reflect.MakeFunc(typ, tr)
		elem.Set(v)
	case reflect.Ptr:
		v := reflect.NewAt(elem.Type().Elem(), handle)
		elem.Set(v)
	case reflect.String:
		elem.SetString(C.GoString(*(**C.char)(handle)))
	case reflect.UnsafePointer:
		elem.SetPointer(handle)
	default:
		return fmt.Errorf("invalid out type %T", out)
	}
	return nil
}