View Issue Details

IDProjectCategoryView StatusLast Update
0002101unrealircdpublic2004-10-07 20:53
ReporterFlop Assigned Tosyzop  
PrioritynormalSeveritycrashReproducibilityalways
Status resolvedResolutionfixed 
PlatformALLOSALLOS VersionALL
Product Version3.2.1 
Fixed in Version3.2.2 
Summary0002101: badword "#" crash the IRCd
DescriptionThis badword entry always freez and crash the IRCd server after a rehash or few seconds after a restart:
badword channel { word "#*"; replace <spam>; };
TagsNo tags attached.
3rd party modules

Activities

syzop

2004-09-30 14:38

administrator   ~0007831

Confirmed on latest CVS [.144].

syzop

2004-09-30 14:42

administrator   ~0007832

Last edited: 2004-10-01 19:30

Now that is fun :p.

243 while (regexec(&this_word->expr, ptr, MAX_MATCH, pmatch,0) != REG_NOMATCH)
(gdb)
245 if (pmatch[0].rm_so == -1)
(gdb)
247 cleaned = 1;
(gdb)
248 matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
(gdb) p pmatch[0].rm_eo
$1 = 0
(gdb) p pmatch[0].rm_so
$2 = 0
(gdb) p matchlen
$3 = 0
(gdb) n
249 strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
(gdb) p matchlen
$4 = 0
(gdb) x/s buf
0xbfffe370: "<spam><spam><spam><spam><spam><spam><spam><spam><spam><spam>
(gdb) x/s ptr
0x80cd220 <cleanstr.0>: "haha"
(gdb) n
250 if (this_word->replace)
(gdb)
251 strlcat(buf, this_word->replace, sizeof buf);
(gdb)
254 ptr += pmatch[0].rm_eo; /* Set pointer after the match pos */
(gdb)
255 memset(&pmatch, 0, sizeof(pmatch));
(gdb)
243 while (regexec(&this_word->expr, ptr, MAX_MATCH, pmatch,0) != REG_NOMATCH)
(gdb)
245 if (pmatch[0].rm_so == -1)
(gdb)
247 cleaned = 1;
(gdb)
248 matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
(gdb) p matchlen
$5 = 0
(gdb) p pmatch[0].rm_eo
$6 = 0
(gdb) p pmatch[0].rm_so
$7 = 0
(gdb) n
249 strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
(gdb) x/s buf
0xbfffe370: "<spam><spam><spam><spam><spam><spam><spam><spam><spam><spam><spam><spam><spam><spam><spam><spam><spam>"...
(gdb) x/s ptr
0x80cd220 <cleanstr.0>: "haha"
(gdb) n
250 if (this_word->replace)
(gdb)
251 strlcat(buf, this_word->replace, sizeof buf);
(gdb) p *this_word
$8 = {prev = 0x819e3a8, next = 0x8183798, flag = {temporary = 0, permanent = 0}, word = 0x819e5f8 "#*",
  replace = 0x819ee90 "<spam>", type = 8, action = 1 '\001', expr = {re_nsub = 0, value = 0x819ee18}}
(gdb) n
254 ptr += pmatch[0].rm_eo; /* Set pointer after the match pos */
(gdb) p ptr
$9 = 0x80cd220 "haha"
(gdb) n
255 memset(&pmatch, 0, sizeof(pmatch));
(gdb) p ptr
$10 = 0x80cd220 "haha"
(gdb) p strlen(buf)
$11 = 4095
(gdb) n
243 while (regexec(&this_word->expr, ptr, MAX_MATCH, pmatch,0) != REG_NOMATCH)
(gdb)
245 if (pmatch[0].rm_so == -1)
(gdb)
247 cleaned = 1;
(gdb)
248 matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
(gdb)
249 strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
(gdb)
250 if (this_word->replace)
(gdb)
251 strlcat(buf, this_word->replace, sizeof buf);
(gdb)
254 ptr += pmatch[0].rm_eo; /* Set pointer after the match pos */
(gdb)
255 memset(&pmatch, 0, sizeof(pmatch));
(gdb)
243 while (regexec(&this_word->expr, ptr, MAX_MATCH, pmatch,0) != REG_NOMATCH)
(gdb)
245 if (pmatch[0].rm_so == -1)
(gdb)
247 cleaned = 1;
(gdb)
248 matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
(gdb)
249 strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
(gdb)
250 if (this_word->replace)
(gdb)
251 strlcat(buf, this_word->replace, sizeof buf);
(gdb)
254 ptr += pmatch[0].rm_eo; /* Set pointer after the match pos */
(gdb)
255 memset(&pmatch, 0, sizeof(pmatch));
(gdb)
243 while (regexec(&this_word->expr, ptr, MAX_MATCH, pmatch,0) != REG_NOMATCH)
(gdb)
245 if (pmatch[0].rm_so == -1)
(gdb)
247 cleaned = 1;
(gdb)
248 matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
(gdb)
249 strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
(gdb)
[etc...]

edited on: 2004-10-01 19:30

syzop

2004-09-30 14:48

administrator   ~0007833

codemastr: should we perhaps break if pmatch[0].rm_eo is 0 or something? Or is there (also) a bug somewhere else (TRE?)? ;)

codemastr

2004-09-30 15:08

reporter   ~0007834

I have no idea :P

Flop

2004-09-30 15:31

reporter   ~0007835

héhéhé ;-)

codemastr

2004-10-01 19:28

reporter   ~0007842

Ok, first this has nothing to do with #. It has to do with empty matches. #* means "match 0 or more #." So, indeed, text like "abc" does match #*. But what part matches it? Well that's obvious, the "empty" part of it (none of the text). So how do you show this? By returning an empty string as the match text. You determine the length of the string by doing pmatch[0].rm_eo - pmatch[0].rm_so. In this case it is 0, so indeed the string is empty. So basically, I think TRE is working exactly as it is designed to work. I tested with the FreeBSD regex library and it did the same thing. I think the solution is pretty easy. Just detect these empty strings. Unfortunately, I'm not quite sure how to do this. I tried as you suggested, breaking when pmatch[0].rm_eo is 0. This doesn't work. For example, if I type "# #" it got changed to "<spam> #" rather than "<spam> <spam>" as it should have. So maybe you have a better idea?

codemastr

2004-10-02 00:14

reporter   ~0007844

Ok, now I'm even more confused than when I started. I figured, since I don't quite know how to handle this, let's see how other people handle it.
PHP:
echo ereg_replace("#*", "@", "# #");
result was "@@ @@"
Same result when using preg_replace.

sed:
echo # #|sed -e "s/#*/@/g"
result was "@@ @"

mIRC:
//echo $regsub(# #,/#*/g,@,%var)
result was "@@ @@"

I tried a few other things, it seems the consensus was "@@ @@." Why sed was different, I have no idea. And I still don't understand why @@ @@ is the correct output, but it seems to be...

syzop

2004-10-07 20:53

administrator   ~0007903

Fixed in CVS [.149]:
- Fix for "match-all regex" in badword *::word causing the IRCd to hang (0002101).

We now (as decided per our discussion):
- check if such a regex matches everything (=error)
- if somehow rm_eo - rm_so == 0 then we break to prevent looping

Issue History

Date Modified Username Field Change
2004-09-30 11:50 Flop New Issue
2004-09-30 14:22 syzop View Status public => private
2004-09-30 14:38 syzop Note Added: 0007831
2004-09-30 14:38 syzop Status new => confirmed
2004-09-30 14:42 syzop Note Added: 0007832
2004-09-30 14:48 syzop Note Added: 0007833
2004-09-30 15:08 codemastr Note Added: 0007834
2004-09-30 15:31 Flop Note Added: 0007835
2004-10-01 19:28 codemastr Note Added: 0007842
2004-10-01 19:30 codemastr Note Edited: 0007832
2004-10-02 00:14 codemastr Note Added: 0007844
2004-10-07 20:46 syzop View Status private => public
2004-10-07 20:53 syzop Status confirmed => resolved
2004-10-07 20:53 syzop Resolution open => fixed
2004-10-07 20:53 syzop Assigned To => syzop
2004-10-07 20:53 syzop Note Added: 0007903
2004-10-07 20:53 syzop Fixed in Version => 3.2.2