mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
fix: memory leak during conference load
This was found in our continous fuzzing setup.
This commit is contained in:
parent
6a6bc029de
commit
12dbafbd18
104
toxcore/group.c
104
toxcore/group.c
|
@ -3392,19 +3392,21 @@ uint8_t *conferences_save(const Group_Chats *g_c, uint8_t *data)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief load_group Load a Group section from a save file
|
||||||
|
* @param g Group to load
|
||||||
|
* @param g_c Reference to all groupchats, need for utility functions
|
||||||
|
* @param data Start of the data to deserialze
|
||||||
|
* @param length Length of data
|
||||||
|
* @return 0 on error, number of consumed bytes otherwise
|
||||||
|
*/
|
||||||
non_null()
|
non_null()
|
||||||
static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data, uint32_t length)
|
static uint32_t load_group(Group_c *g, const Group_Chats *g_c, const uint8_t *data, uint32_t length)
|
||||||
{
|
{
|
||||||
const uint8_t *init_data = data;
|
const uint8_t *init_data = data;
|
||||||
|
|
||||||
while (length >= (uint32_t)(data - init_data) + SAVED_CONF_SIZE_CONSTANT) {
|
// Initialize to default values so we can unconditionally free in case of an error
|
||||||
const int groupnumber = create_group_chat(g_c);
|
setup_conference(g);
|
||||||
|
|
||||||
if (groupnumber == -1) {
|
|
||||||
return STATE_LOAD_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
Group_c *g = &g_c->chats[groupnumber];
|
|
||||||
|
|
||||||
g->type = *data;
|
g->type = *data;
|
||||||
++data;
|
++data;
|
||||||
|
@ -3428,28 +3430,34 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,
|
||||||
g->frozen = (Group_Peer *)calloc(g->numfrozen, sizeof(Group_Peer));
|
g->frozen = (Group_Peer *)calloc(g->numfrozen, sizeof(Group_Peer));
|
||||||
|
|
||||||
if (g->frozen == nullptr) {
|
if (g->frozen == nullptr) {
|
||||||
return STATE_LOAD_STATUS_ERROR;
|
// Memory allocation failure
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g->title_len = *data;
|
g->title_len = *data;
|
||||||
|
|
||||||
if (g->title_len > MAX_NAME_LENGTH) {
|
if (g->title_len > MAX_NAME_LENGTH) {
|
||||||
return STATE_LOAD_STATUS_ERROR;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
++data;
|
++data;
|
||||||
|
|
||||||
|
assert((data - init_data) < UINT32_MAX);
|
||||||
|
|
||||||
if (length < (uint32_t)(data - init_data) + g->title_len) {
|
if (length < (uint32_t)(data - init_data) + g->title_len) {
|
||||||
return STATE_LOAD_STATUS_ERROR;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(g->title, data, g->title_len);
|
memcpy(g->title, data, g->title_len);
|
||||||
data += g->title_len;
|
data += g->title_len;
|
||||||
|
|
||||||
for (uint32_t j = 0; j < g->numfrozen; ++j) {
|
for (uint32_t j = 0; j < g->numfrozen; ++j) {
|
||||||
|
|
||||||
|
assert((data - init_data) < UINT32_MAX);
|
||||||
|
|
||||||
if (length < (uint32_t)(data - init_data) + SAVED_PEER_SIZE_CONSTANT) {
|
if (length < (uint32_t)(data - init_data) + SAVED_PEER_SIZE_CONSTANT) {
|
||||||
return STATE_LOAD_STATUS_ERROR;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group_Peer *peer = &g->frozen[j];
|
Group_Peer *peer = &g->frozen[j];
|
||||||
|
@ -3469,13 +3477,14 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,
|
||||||
peer->nick_len = *data;
|
peer->nick_len = *data;
|
||||||
|
|
||||||
if (peer->nick_len > MAX_NAME_LENGTH) {
|
if (peer->nick_len > MAX_NAME_LENGTH) {
|
||||||
return STATE_LOAD_STATUS_ERROR;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
++data;
|
++data;
|
||||||
|
assert((data - init_data) < UINT32_MAX);
|
||||||
|
|
||||||
if (length < (uint32_t)(data - init_data) + peer->nick_len) {
|
if (length < (uint32_t)(data - init_data) + peer->nick_len) {
|
||||||
return STATE_LOAD_STATUS_ERROR;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(peer->nick, data, peer->nick_len);
|
memcpy(peer->nick, data, peer->nick_len);
|
||||||
|
@ -3490,7 +3499,49 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
g->status = GROUPCHAT_STATUS_CONNECTED;
|
g->status = GROUPCHAT_STATUS_CONNECTED;
|
||||||
memcpy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE);
|
|
||||||
|
id_copy(g->real_pk, nc_get_self_public_key(g_c->m->net_crypto));
|
||||||
|
|
||||||
|
assert((data - init_data) < UINT32_MAX);
|
||||||
|
|
||||||
|
return (uint32_t)(data - init_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
non_null()
|
||||||
|
static State_Load_Status load_conferences_helper(Group_Chats *g_c, const uint8_t *data, uint32_t length)
|
||||||
|
{
|
||||||
|
const uint8_t *init_data = data;
|
||||||
|
|
||||||
|
while (length >= (uint32_t)(data - init_data) + SAVED_CONF_SIZE_CONSTANT) {
|
||||||
|
const int groupnumber = create_group_chat(g_c);
|
||||||
|
|
||||||
|
// Helpful for testing
|
||||||
|
assert(groupnumber != -1);
|
||||||
|
|
||||||
|
if (groupnumber == -1) {
|
||||||
|
// If this fails there's a serious problem, don't bother with cleanup
|
||||||
|
return STATE_LOAD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Group_c *g = &g_c->chats[groupnumber];
|
||||||
|
|
||||||
|
const uint32_t consumed = load_group(g, g_c, data, length - (uint32_t)(data - init_data));
|
||||||
|
|
||||||
|
if (consumed == 0) {
|
||||||
|
// remove partially loaded stuff, wipe_group_chat must be able to wipe a partially loaded group
|
||||||
|
const bool ret = wipe_group_chat(g_c, groupnumber);
|
||||||
|
|
||||||
|
// HACK: suppress unused variable warning
|
||||||
|
if (!ret) {
|
||||||
|
// wipe_group_chat(...) must be able to wipe partially allocated groups
|
||||||
|
assert(ret == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATE_LOAD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += consumed;
|
||||||
|
|
||||||
const int peer_index = addpeer(g_c, groupnumber, g->real_pk, dht_get_self_public_key(g_c->m->dht), g->peer_number,
|
const int peer_index = addpeer(g_c, groupnumber, g->real_pk, dht_get_self_public_key(g_c->m->dht), g->peer_number,
|
||||||
nullptr, true, false);
|
nullptr, true, false);
|
||||||
|
|
||||||
|
@ -3504,6 +3555,27 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data,
|
||||||
return STATE_LOAD_STATUS_CONTINUE;
|
return STATE_LOAD_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
non_null()
|
||||||
|
static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data, uint32_t length)
|
||||||
|
{
|
||||||
|
const State_Load_Status res = load_conferences_helper(g_c, data, length);
|
||||||
|
|
||||||
|
if (res == STATE_LOAD_STATUS_CONTINUE) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading failed, cleanup all Group_c
|
||||||
|
|
||||||
|
// save locally, because wipe_group_chat(...) modifies it
|
||||||
|
const uint16_t num_groups = g_c->num_chats;
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < num_groups; ++i) {
|
||||||
|
wipe_group_chat(g_c, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
|
bool conferences_load_state_section(Group_Chats *g_c, const uint8_t *data, uint32_t length, uint16_t type,
|
||||||
State_Load_Status *status)
|
State_Load_Status *status)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user