Remove queueing of wildcard CSETs and fix use-after-free with queued CSETs
A queued CSET is one that is set before the matching channel is joined. The CSetList is allocated and linked to the cset_queue list. The use-after-free bug was caused because the CSetList wasn't removed from the cset_queue after it was attached to a joined channel. If the channel is parted, it eventually ages out of the Whowas-Chan-List and the CSetList is freed, but there is now a dangling pointer to it in the cset_queue. This is fixed by removing the CSetList from the cset_queue when it is attached to a channel, so the net result of /CSET #chan ; /JOIN #chan is the same as doing the reverse. Queued wildcard CSETs never worked properly - the queued CSET with the wildcard name would end up attached to any subsequent matching channel that was joined. Channel names with wildcards in them are legal anyway, so the best medium-term solution (pending a full redesign of the whole CSET command) is to just enforce that queued CSETs are always literal channel names, not wildcards.
This commit is contained in:
parent
f714e3e951
commit
ddfbec0b4b
|
@ -1,5 +1,8 @@
|
|||
[Changes 1.2.2]
|
||||
|
||||
* Remove queueing of wildcard CSETs and fix use-after-free with queued
|
||||
CSETs. (caf)
|
||||
|
||||
* Bump MAXPARA (maximum protocol message arguments) to 20 as per EPIC5. (caf)
|
||||
|
||||
* Correctly handle a last argument prefixed with : for any protocol message,
|
||||
|
|
|
@ -325,34 +325,15 @@ static void set_cset_var_value(CSetList *tmp, int var_index, char *value)
|
|||
|
||||
CSetList *check_cset_queue(char *channel, int add)
|
||||
{
|
||||
CSetList *c = NULL;
|
||||
int found = 0;
|
||||
if (!strchr(channel, '*') && !(c = (CSetList *)find_in_list((List **)&cset_queue, channel, 0)))
|
||||
CSetList *c = (CSetList *)find_in_list((List **)&cset_queue, channel, 0);
|
||||
|
||||
if (!c && add)
|
||||
{
|
||||
if (!add)
|
||||
{
|
||||
for (c = cset_queue; c; c = c->next)
|
||||
if (!my_stricmp(c->channel, channel) || wild_match(c->channel, channel))
|
||||
return c;
|
||||
return NULL;
|
||||
}
|
||||
c = create_csets_for_channel(channel);
|
||||
add_to_list((List **)&cset_queue, (List *)c);
|
||||
found++;
|
||||
}
|
||||
if (c)
|
||||
return c;
|
||||
if (add && !found)
|
||||
{
|
||||
for (c = cset_queue; c; c = c->next)
|
||||
if (!my_stricmp(c->channel, channel))
|
||||
return c;
|
||||
c = create_csets_for_channel(channel);
|
||||
c->next = cset_queue;
|
||||
cset_queue = c;
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline void cset_variable_range(char *channel, int cnt, int var_index, char *args)
|
||||
|
@ -541,14 +522,9 @@ CSetList *create_csets_for_channel(char *channel)
|
|||
ircpanic("Variable [%d] (%s) is out of order.", i, cset_array[i].name);
|
||||
#endif
|
||||
|
||||
if (check_cset_queue(channel, 0))
|
||||
{
|
||||
if ((tmp = (CSetList *)find_in_list((List **)&cset_queue, channel, 0)))
|
||||
return tmp;
|
||||
for (tmp = cset_queue; tmp; tmp = tmp->next)
|
||||
if (!my_stricmp(tmp->channel, channel) || wild_match(tmp->channel, channel))
|
||||
return tmp;
|
||||
}
|
||||
if ((tmp = (CSetList *)remove_from_list((List **)&cset_queue, channel)))
|
||||
return tmp;
|
||||
|
||||
tmp = (CSetList *) new_malloc(sizeof(CSetList));
|
||||
/* use default settings. */
|
||||
tmp->set_aop = get_int_var(AOP_VAR);
|
||||
|
|
Loading…
Reference in New Issue