eggheads / eggdrop

The Eggdrop IRC Bot
GNU General Public License v2.0
494 stars 88 forks source link

Add HOOK for reset (channel) member #1610

Open michaelortmann opened 2 weeks ago

michaelortmann commented 2 weeks ago

Found by: michaelortmann Patch by: michaelortmann Fixes:

One-line summary: Add HOOK for reset (channel) member

Additional description (if needed): stats.mod caches the result of ismember() up to 1 minute and suffers a heap-use-after-free when eggdrop frees members during a channel reset here: https://github.com/eggheads/eggdrop/blob/d58f56347a16947757a0112715b13561f49fb539/src/mod/channels.mod/tclchan.c#L2006C9-L2006C10

With this PR combined with https://github.com/michaelortmann/stats.mod/commit/02ff9916b33e2e5d879a1d09989a16dffa6fb6ed stats.mod will add a new hook that channel.mod will trigger. when channel.mod resets channel members it will call that hook and stats.mod will resync.

Test cases demonstrating functionality (if applicable): With stats.mod Before:

[11:08:51] [!s] WHOIS BotA
[11:08:57] [s->] WHOIS BotA
[11:08:57] [@] :irc.example.org 311 BotA BotA eggdrop Clk-8553FB0D * :A deranged product of evil coders
[11:08:57] [@] :irc.example.org 379 BotA BotA :is using modes +ix 
[11:08:57] [@] :irc.example.org 378 BotA BotA :is connecting from *@localhost 127.0.0.1
[11:08:57] [@] :irc.example.org 312 BotA BotA irc.example.org :ExampleNET Server
[11:08:57] [@] :irc.example.org 317 BotA BotA 8 1718096929 :seconds idle, signon time
[11:08:57] [@] :irc.example.org 318 BotA BotA :End of /WHOIS list.
[11:08:59] [s->] JOIN #test
[11:08:59] [@] :BotA!eggdrop@Clk-8553FB0D JOIN #test * :A deranged product of evil coders
[11:08:59] BotA joined #test.
[11:08:59] [!m] MODE #test +b
[11:08:59] [m->] MODE #test +b
[11:08:59] [!m] MODE #test +e
[11:08:59] [m->] MODE #test +e
[11:08:59] [!m] MODE #test +I
[11:08:59] [!m] MODE #test
[11:08:59] [!m] WHO #test c%chnufat,222
[11:08:59] [@] :irc.example.org MODE #test +nt 
[11:08:59] #test: mode change '+nt ' by irc.example.org
[11:08:59] [@] :irc.example.org 353 BotA = #test :@BotA
[11:08:59] [@] :irc.example.org 366 BotA #test :End of /NAMES list.
[11:08:59] [@] :irc.example.org 368 BotA #test :End of Channel Ban List
[11:08:59] [@] :irc.example.org 349 BotA #test :End of Channel Exception List
[11:09:01] [m->] MODE #test +I
[11:09:01] [@] :irc.example.org 347 BotA #test :End of Channel Invite List
[11:09:02] net: connect! sock 6
[11:09:02] 127.0.0.1: GET /test/onchan/ HTTP/1.1
[11:09:02] 127.0.0.1: Host: 127.0.0.1:8033
[11:09:02] 127.0.0.1: User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:126.0) Gecko/20100101 Firefox/126.0
[11:09:02] 127.0.0.1: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
[11:09:02] 127.0.0.1: Accept-Language: en-US,en;q=0.5
[11:09:02] adding accepted language: 'en'
[11:09:02] adding accepted language: 'en'
[11:09:02] 127.0.0.1: Accept-Encoding: gzip, deflate, br, zstd
[11:09:02] 127.0.0.1: Referer: http://127.0.0.1:8033/test/
[11:09:02] 127.0.0.1: Connection: keep-alive
[11:09:02] 127.0.0.1: Upgrade-Insecure-Requests: 1
[11:09:02] 127.0.0.1: Sec-Fetch-Dest: document
[11:09:02] 127.0.0.1: Sec-Fetch-Mode: navigate
[11:09:02] 127.0.0.1: Sec-Fetch-Site: same-origin
[11:09:02] 127.0.0.1: Sec-Fetch-User: ?1
[11:09:02] 127.0.0.1: Priority: u=1
[11:09:02] 127.0.0.1: Pragma: no-cache
[11:09:02] 127.0.0.1: Cache-Control: no-cache
[11:09:02] 127.0.0.1: 
[11:09:02] now sending...
=================================================================
==2274420==ERROR: AddressSanitizer: heap-use-after-free on address 0x515000002a10 at pc 0x7e28589765fe bp 0x7ffe6e7b1880 sp 0x7ffe6e7b1870
READ of size 8 at 0x515000002a10 thread T0
    #0 0x7e28589765fd in template_send_usermode core/templates_stats_commands.c:1000
    #1 0x7e2858966d96 in templates_content_send core/templates_content.c:251
    #2 0x7e2858976406 in template_send_onchanlist core/templates_stats_commands.c:992
    #3 0x7e2858966d96 in templates_content_send core/templates_content.c:251
    #4 0x7e285896b5c0 in template_send core/templates.c:165
    #5 0x7e2858980829 in process_get_request core/http_processing.c:327
    #6 0x7e285893cd66 in http_activity core/mini_httpd.c:390
    #7 0x6095dd728adc in mainloop main.c:797
    #8 0x6095dd72ce37 in main main.c:1213
    #9 0x7e285d239c87  (/usr/lib/libc.so.6+0x25c87) (BuildId: 32a656aa5562eece8c59a585f5eacd6cf5e2307b)
    #10 0x7e285d239d4b in __libc_start_main (/usr/lib/libc.so.6+0x25d4b) (BuildId: 32a656aa5562eece8c59a585f5eacd6cf5e2307b)
    #11 0x6095dd63f4a4 in _start (/home/michael/eggdrop/eggdrop-1.9.5+0x2774a4) (BuildId: 61a3415c7de8a5b01975ffb1e0922903878400f5)

0x515000002a10 is located 400 bytes inside of 456-byte region [0x515000002880,0x515000002a48)
freed by thread T0 here:
    #0 0x7e285e4fb422 in free /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:52
    #1 0x6095dd731b17 in n_free /home/michael/projects/eggdrop/src/mem.c:443
    #2 0x6095dd74774f in mod_free /home/michael/projects/eggdrop/src/modules.c:1033
    #3 0x7e2859941d33 in init_channel .././channels.mod/tclchan.c:2006
    #4 0x7e285994334f in clear_channel .././channels.mod/tclchan.c:2085
    #5 0x7e28593d95bd in reset_chan_info .././irc.mod/irc.c:423
    #6 0x7e28593588f0 in gotjoin .././irc.mod/chan.c:2120
    #7 0x7e2859712fee in server_raw .././server.mod/server.c:1410
    #8 0x6095dd769bfa in tcl_call_stringproc_cd /home/michael/projects/eggdrop/src/tcl.c:332
    #9 0x7e285e27e7ff in TclNRRunCallbacks /usr/src/debug/tcl/tcl8.6.14/generic/tclBasic.c:4539

previously allocated by thread T0 here:
    #0 0x7e285e4fca31 in malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x6095dd7304ea in n_malloc /home/michael/projects/eggdrop/src/mem.c:342
    #2 0x6095dd7472b6 in mod_malloc /home/michael/projects/eggdrop/src/modules.c:1005
    #3 0x7e2859941e45 in init_channel .././channels.mod/tclchan.c:2009
    #4 0x7e285994478f in tcl_channel_add .././channels.mod/tclchan.c:2154
    #5 0x7e285992f09d in tcl_channel .././channels.mod/tclchan.c:1253
    #6 0x6095dd769bfa in tcl_call_stringproc_cd /home/michael/projects/eggdrop/src/tcl.c:332
    #7 0x6095dd769d1b in tcl_call_stringproc /home/michael/projects/eggdrop/src/tcl.c:341
    #8 0x7e285e27e7ff in TclNRRunCallbacks /usr/src/debug/tcl/tcl8.6.14/generic/tclBasic.c:4539

SUMMARY: AddressSanitizer: heap-use-after-free core/templates_stats_commands.c:1000 in template_send_usermode
Shadow bytes around the buggy address:
  0x515000002780: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x515000002800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x515000002880: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x515000002900: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x515000002980: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x515000002a00: fd fd[fd]fd fd fd fd fd fd fa fa fa fa fa fa fa
  0x515000002a80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x515000002b00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x515000002b80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x515000002c00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x515000002c80: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==2274420==ABORTING

After:

[11:13:42] [!s] WHOIS BotA
[11:13:48] [s->] WHOIS BotA
[11:13:48] [@] :irc.example.org 311 BotA BotA eggdrop Clk-8553FB0D * :A deranged product of evil coders
[11:13:48] [@] :irc.example.org 379 BotA BotA :is using modes +ix 
[11:13:48] [@] :irc.example.org 378 BotA BotA :is connecting from *@localhost 127.0.0.1
[11:13:48] [@] :irc.example.org 312 BotA BotA irc.example.org :ExampleNET Server
[11:13:48] [@] :irc.example.org 317 BotA BotA 8 1718097220 :seconds idle, signon time
[11:13:48] [@] :irc.example.org 318 BotA BotA :End of /WHOIS list.
[11:13:50] [s->] JOIN #test
[11:13:50] [@] :BotA!eggdrop@Clk-8553FB0D JOIN #test * :A deranged product of evil coders
[11:13:50] BotA joined #test.
[11:13:50] Channel '#test' desynched: 0 eggmembers vs 1 statsmembers. Resynching...
[11:13:50] [!m] MODE #test +b
[11:13:50] [m->] MODE #test +b
[11:13:50] [!m] MODE #test +e
[11:13:50] [m->] MODE #test +e
[11:13:50] [!m] MODE #test +I
[11:13:50] [!m] MODE #test
[11:13:50] [!m] WHO #test c%chnufat,222
[11:13:50] [@] :irc.example.org MODE #test +nt 
[11:13:50] #test: mode change '+nt ' by irc.example.org
[11:13:50] [@] :irc.example.org 353 BotA = #test :@BotA
[11:13:50] [@] :irc.example.org 366 BotA #test :End of /NAMES list.
[11:13:50] [@] :irc.example.org 368 BotA #test :End of Channel Ban List
[11:13:50] [@] :irc.example.org 349 BotA #test :End of Channel Exception List
[11:13:52] net: connect! sock 6
[11:13:52] [m->] MODE #test +I
[11:13:52] [@] :irc.example.org 347 BotA #test :End of Channel Invite List
[11:13:52] 127.0.0.1: GET /test/onchan/ HTTP/1.1
[11:13:52] 127.0.0.1: Host: 127.0.0.1:8033
[11:13:52] 127.0.0.1: User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:126.0) Gecko/20100101 Firefox/126.0
[11:13:52] 127.0.0.1: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
[11:13:52] 127.0.0.1: Accept-Language: en-US,en;q=0.5
[11:13:52] adding accepted language: 'en'
[11:13:52] adding accepted language: 'en'
[11:13:52] 127.0.0.1: Accept-Encoding: gzip, deflate, br, zstd
[11:13:52] 127.0.0.1: Referer: http://127.0.0.1:8033/test/
[11:13:52] 127.0.0.1: Connection: keep-alive
[11:13:52] 127.0.0.1: Upgrade-Insecure-Requests: 1
[11:13:52] 127.0.0.1: Sec-Fetch-Dest: document
[11:13:52] 127.0.0.1: Sec-Fetch-Mode: navigate
[11:13:52] 127.0.0.1: Sec-Fetch-Site: same-origin
[11:13:52] 127.0.0.1: Sec-Fetch-User: ?1
[11:13:52] 127.0.0.1: Priority: u=1
[11:13:52] 127.0.0.1: Pragma: no-cache
[11:13:52] 127.0.0.1: Cache-Control: no-cache
[11:13:52] 127.0.0.1: 
[11:13:52] now sending...
[11:13:52] Processing time: 0.000
[11:13:52] net: connect! sock 6
[11:13:52] 127.0.0.1: GET /favicon.ico HTTP/1.1
[11:13:52] 127.0.0.1: Host: 127.0.0.1:8033
[11:13:52] 127.0.0.1: User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:126.0) Gecko/20100101 Firefox/126.0
[11:13:52] 127.0.0.1: Accept: image/avif,image/webp,*/*
[11:13:52] 127.0.0.1: Accept-Language: en-US,en;q=0.5
[11:13:52] adding accepted language: 'en'
[11:13:52] adding accepted language: 'en'
[11:13:52] 127.0.0.1: Accept-Encoding: gzip, deflate, br, zstd
[11:13:52] 127.0.0.1: Connection: keep-alive
[11:13:52] 127.0.0.1: Referer: http://127.0.0.1:8033/test/onchan/
[11:13:52] 127.0.0.1: Sec-Fetch-Dest: image
[11:13:52] 127.0.0.1: Sec-Fetch-Mode: no-cors
[11:13:52] 127.0.0.1: Sec-Fetch-Site: same-origin
[11:13:52] 127.0.0.1: Priority: u=6
[11:13:52] 127.0.0.1: Pragma: no-cache
[11:13:52] 127.0.0.1: Cache-Control: no-cache
[11:13:52] 127.0.0.1: 
[11:13:52] now sending...
[11:13:52] Processing time: 0.000
[11:13:52] net: connect! sock 6
[11:13:52] 127.0.0.1: GET /favicon.ico/ HTTP/1.1
[11:13:52] 127.0.0.1: Host: 127.0.0.1:8033
[11:13:52] 127.0.0.1: User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:126.0) Gecko/20100101 Firefox/126.0
[11:13:52] 127.0.0.1: Accept: image/avif,image/webp,*/*
[11:13:52] 127.0.0.1: Accept-Language: en-US,en;q=0.5
[11:13:52] adding accepted language: 'en'
[11:13:52] adding accepted language: 'en'
[11:13:52] 127.0.0.1: Accept-Encoding: gzip, deflate, br, zstd
[11:13:52] 127.0.0.1: Referer: http://127.0.0.1:8033/test/onchan/
[11:13:52] 127.0.0.1: Connection: keep-alive
[11:13:52] 127.0.0.1: Sec-Fetch-Dest: image
[11:13:52] 127.0.0.1: Sec-Fetch-Mode: no-cors
[11:13:52] 127.0.0.1: Sec-Fetch-Site: same-origin
[11:13:52] 127.0.0.1: Priority: u=6
[11:13:52] 127.0.0.1: Pragma: no-cache
[11:13:52] 127.0.0.1: Cache-Control: no-cache
[11:13:52] 127.0.0.1: 
[11:13:52] now sending...
[11:13:52] Processing time: 0.000