From b4f4f5600298436c63b89f289c318d777300c499 Mon Sep 17 00:00:00 2001 From: Jeroen Wijenbergh Date: Wed, 13 Aug 2025 14:06:28 +0200 Subject: Exports: Attempt to fix ARM MTE crash --- exports/exports.go | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'exports') diff --git a/exports/exports.go b/exports/exports.go index 880101a..47b9f14 100644 --- a/exports/exports.go +++ b/exports/exports.go @@ -33,6 +33,24 @@ import ( "codeberg.org/eduVPN/eduvpn-common/util" ) +// goString copies a null-terminated *C.char to a Go string. +// the default C.GoString doesn't play well with ARM MTE +// see: https://github.com/golang/go/issues/27610#issuecomment-2381919857 +// see also: https://codeberg.org/eduVPN/android/issues/31 +// this was changed from: https://github.com/ebitengine/purego/blob/77ed15346fbb448af291a0509e024e06252a428f/internal/strings/strings.go#L25C1-L40C2 +// License: https://github.com/ebitengine/purego/blob/77ed15346fbb448af291a0509e024e06252a428f/LICENSE +func goString(c *C.char) string { + ptr := unsafe.Pointer(c) + if ptr == nil { + return "" + } + length := 0 + for *(*byte)(unsafe.Add(ptr, uintptr(length))) != '\x00' { + length++ + } + return C.GoStringN(c, C.int(length)) +} + // VPNState is the current state of the library var VPNState *client.Client @@ -144,9 +162,9 @@ func Register( return getCError(i18nerr.NewInternal("failed to register, a VPN state is already present")) } c, err := client.New( - C.GoString(name), - C.GoString(version), - C.GoString(configDirectory), + goString(name), + goString(version), + goString(configDirectory), func(oldState client.FSMStateID, newState client.FSMStateID, data interface{}) bool { return stateCallback(cb, oldState, newState, data) }, @@ -297,7 +315,7 @@ func AddServer(c C.uintptr_t, _type C.int, id *C.char, ot *C.longlong) *C.char { got := int64(*ot) auth = &got } - err = state.AddServer(v, C.GoString(id), srvtypes.Type(_type), auth) + err = state.AddServer(v, goString(id), srvtypes.Type(_type), auth) return getCError(err) } @@ -331,7 +349,7 @@ func RemoveServer(_type C.int, id *C.char) *C.char { if stateErr != nil { return getCError(stateErr) } - err := state.RemoveServer(C.GoString(id), srvtypes.Type(_type)) + err := state.RemoveServer(goString(id), srvtypes.Type(_type)) return getCError(err) } @@ -547,7 +565,7 @@ func GetConfig(c C.uintptr_t, _type C.int, id *C.char, pTCP C.int, startup C.int } preferTCPBool := pTCP != 0 startupBool := startup != 0 - cfg, err := state.GetConfig(ck, C.GoString(id), srvtypes.Type(_type), preferTCPBool, startupBool) + cfg, err := state.GetConfig(ck, goString(id), srvtypes.Type(_type), preferTCPBool, startupBool) if cfg != nil && err == nil { d, err := getReturnData(cfg) if err == nil { @@ -581,7 +599,7 @@ func SetProfileID(data *C.char) *C.char { if stateErr != nil { return getCError(stateErr) } - profileErr := state.SetProfileID(C.GoString(data)) + profileErr := state.SetProfileID(goString(data)) return getCError(profileErr) } @@ -610,7 +628,7 @@ func SetSecureLocation(orgID *C.char, cc *C.char) *C.char { if stateErr != nil { return getCError(stateErr) } - locationErr := state.SetSecureLocation(C.GoString(orgID), C.GoString(cc)) + locationErr := state.SetSecureLocation(goString(orgID), goString(cc)) return getCError(locationErr) } @@ -669,7 +687,7 @@ func DiscoServers(c C.uintptr_t, search *C.char) (*C.char, *C.char) { if err != nil { return nil, getCError(err) } - servers, err := state.DiscoServers(ck, C.GoString(search)) + servers, err := state.DiscoServers(ck, goString(search)) if servers == nil && err != nil { return nil, getCError(err) } @@ -744,7 +762,7 @@ func DiscoOrganizations(c C.uintptr_t, search *C.char) (*C.char, *C.char) { if err != nil { return nil, getCError(err) } - orgs, err := state.DiscoOrganizations(ck, C.GoString(search)) + orgs, err := state.DiscoOrganizations(ck, goString(search)) if orgs == nil && err != nil { return nil, getCError(err) } @@ -846,7 +864,7 @@ func StartFailover(c C.uintptr_t, gateway *C.char, mtu C.int, readRxBytes C.Read if err != nil { return C.int(0), getCError(err) } - dropped, droppedErr := state.StartFailover(ck, C.GoString(gateway), int(mtu), func() (int64, error) { + dropped, droppedErr := state.StartFailover(ck, goString(gateway), int(mtu), func() (int64, error) { rxBytes := int64(C.get_read_rx_bytes(readRxBytes)) if rxBytes < 0 { return 0, i18nerr.NewInternal("client gave an invalid rx bytes value") @@ -1035,7 +1053,7 @@ func SetTokenHandler(getter C.TokenGetter, setter C.TokenSetter) *C.char { // //export CalculateGateway func CalculateGateway(subnet *C.char) (*C.char, *C.char) { - gw, err := util.CalculateGateway(C.GoString(subnet)) + gw, err := util.CalculateGateway(goString(subnet)) if err != nil { return nil, getCError(err) } @@ -1076,7 +1094,7 @@ func CookieReply(c C.uintptr_t, data *C.char) *C.char { if err != nil { return getCError(err) } - err = v.Send(C.GoString(data)) + err = v.Send(goString(data)) return getCError(err) } -- cgit v1.2.3