From d74392c36561e7b1e8eca5c1e43f3cc4ab0ff0a5 Mon Sep 17 00:00:00 2001 From: Stefan Siegel Date: Sun, 11 Jun 2023 18:39:18 +0200 Subject: [PATCH] Pass char* to Go and convert with C.GoString, avoiding unsafe use Using the char* passed by Mosquitto in a GoString struct is unsafe. The memory it points to is managed by Mosquitto, but Go will keep the pointer around for an indefinite duration, even when Mosquitto might free the memory. By passing the actual char* to Go, we can use C.GoString to convert it, which copies the bytes into a buffer managed by Go. That way we can use it safely at any time in the future. --- auth-plugin.c | 26 +++++++------------------- go-auth.go | 14 +++++++------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/auth-plugin.c b/auth-plugin.c index a1c23ce..fc45f26 100644 --- a/auth-plugin.c +++ b/auth-plugin.c @@ -38,15 +38,13 @@ int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_auth_opt *auth GoInt32 opts_count = auth_opt_count; - GoString keys[auth_opt_count]; - GoString values[auth_opt_count]; + char *keys[auth_opt_count]; + char *values[auth_opt_count]; int i; struct mosquitto_auth_opt *o; for (i = 0, o = auth_opts; i < auth_opt_count; i++, o++) { - GoString opt_key = {o->key, strlen(o->key)}; - GoString opt_value = {o->value, strlen(o->value)}; - keys[i] = opt_key; - values[i] = opt_value; + keys[i] = o->key; + values[i] = o->value; } GoSlice keysSlice = {keys, auth_opt_count, auth_opt_count}; @@ -55,9 +53,8 @@ int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_auth_opt *auth char versionArray[10]; sprintf(versionArray, "%i.%i.%i", LIBMOSQUITTO_MAJOR, LIBMOSQUITTO_MINOR, LIBMOSQUITTO_REVISION); - GoString version = {versionArray, strlen(versionArray)}; - AuthPluginInit(keysSlice, valuesSlice, opts_count, version); + AuthPluginInit(keysSlice, valuesSlice, opts_count, versionArray); return MOSQ_ERR_SUCCESS; } @@ -93,11 +90,7 @@ int mosquitto_auth_unpwd_check(void *userdata, const char *username, const char return MOSQ_ERR_AUTH; } - GoString go_username = {username, strlen(username)}; - GoString go_password = {password, strlen(password)}; - GoString go_clientid = {clientid, strlen(clientid)}; - - GoUint8 ret = AuthUnpwdCheck(go_username, go_password, go_clientid); + GoUint8 ret = AuthUnpwdCheck((char *)username, (char *)password, (char *)clientid); switch (ret) { @@ -135,12 +128,7 @@ int mosquitto_auth_acl_check(void *userdata, const char *clientid, const char *u return MOSQ_ERR_ACL_DENIED; } - GoString go_clientid = {clientid, strlen(clientid)}; - GoString go_username = {username, strlen(username)}; - GoString go_topic = {topic, strlen(topic)}; - GoInt32 go_access = access; - - GoUint8 ret = AuthAclCheck(go_clientid, go_username, go_topic, go_access); + GoUint8 ret = AuthAclCheck((char *)clientid, (char *)username, (char *)topic, access); switch (ret) { diff --git a/go-auth.go b/go-auth.go index 2768528..32bac7c 100644 --- a/go-auth.go +++ b/go-auth.go @@ -38,7 +38,7 @@ var authOpts map[string]string //Options passed by mosquitto. var authPlugin AuthPlugin //General struct with options and conf. //export AuthPluginInit -func AuthPluginInit(keys []string, values []string, authOptsNum int, version string) { +func AuthPluginInit(keys []*C.char, values []*C.char, authOptsNum int, version *C.char) { log.SetFormatter(&log.TextFormatter{ FullTimestamp: true, }) @@ -51,7 +51,7 @@ func AuthPluginInit(keys []string, values []string, authOptsNum int, version str authOpts = make(map[string]string) for i := 0; i < authOptsNum; i++ { - authOpts[keys[i]] = values[i] + authOpts[C.GoString(keys[i])] = C.GoString(values[i]) } if retryCount, ok := authOpts["retry_count"]; ok { @@ -104,7 +104,7 @@ func AuthPluginInit(keys []string, values []string, authOptsNum int, version str var err error - authPlugin.backends, err = bes.Initialize(authOpts, authPlugin.logLevel, version) + authPlugin.backends, err = bes.Initialize(authOpts, authPlugin.logLevel, C.GoString(version)) if err != nil { log.Fatalf("error initializing backends: %s", err) } @@ -276,12 +276,12 @@ func setCache(authOpts map[string]string) { } //export AuthUnpwdCheck -func AuthUnpwdCheck(username, password, clientid string) uint8 { +func AuthUnpwdCheck(username, password, clientid *C.char) uint8 { var ok bool var err error for try := 0; try <= authPlugin.retryCount; try++ { - ok, err = authUnpwdCheck(username, password, clientid) + ok, err = authUnpwdCheck(C.GoString(username), C.GoString(password), C.GoString(clientid)) if err == nil { break } @@ -330,12 +330,12 @@ func authUnpwdCheck(username, password, clientid string) (bool, error) { } //export AuthAclCheck -func AuthAclCheck(clientid, username, topic string, acc int) uint8 { +func AuthAclCheck(clientid, username, topic *C.char, acc C.int) uint8 { var ok bool var err error for try := 0; try <= authPlugin.retryCount; try++ { - ok, err = authAclCheck(clientid, username, topic, acc) + ok, err = authAclCheck(C.GoString(clientid), C.GoString(username), C.GoString(topic), int(acc)) if err == nil { break }