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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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()
|
||||
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;
|
||||
|
||||
while (length >= (uint32_t)(data - init_data) + SAVED_CONF_SIZE_CONSTANT) {
|
||||
const int groupnumber = create_group_chat(g_c);
|
||||
|
||||
if (groupnumber == -1) {
|
||||
return STATE_LOAD_STATUS_ERROR;
|
||||
}
|
||||
|
||||
Group_c *g = &g_c->chats[groupnumber];
|
||||
// Initialize to default values so we can unconditionally free in case of an error
|
||||
setup_conference(g);
|
||||
|
||||
g->type = *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));
|
||||
|
||||
if (g->frozen == nullptr) {
|
||||
return STATE_LOAD_STATUS_ERROR;
|
||||
// Memory allocation failure
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
g->title_len = *data;
|
||||
|
||||
if (g->title_len > MAX_NAME_LENGTH) {
|
||||
return STATE_LOAD_STATUS_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
++data;
|
||||
|
||||
assert((data - init_data) < UINT32_MAX);
|
||||
|
||||
if (length < (uint32_t)(data - init_data) + g->title_len) {
|
||||
return STATE_LOAD_STATUS_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(g->title, data, g->title_len);
|
||||
data += g->title_len;
|
||||
|
||||
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) {
|
||||
return STATE_LOAD_STATUS_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (peer->nick_len > MAX_NAME_LENGTH) {
|
||||
return STATE_LOAD_STATUS_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
++data;
|
||||
assert((data - init_data) < UINT32_MAX);
|
||||
|
||||
if (length < (uint32_t)(data - init_data) + peer->nick_len) {
|
||||
return STATE_LOAD_STATUS_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
State_Load_Status *status)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user