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.
This commit is contained in:
Stefan Siegel 2023-06-11 18:39:18 +02:00
parent 807e8f25e3
commit d74392c365
2 changed files with 14 additions and 26 deletions

View File

@ -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)
{

View File

@ -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
}