CVE-2020-8955: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow') (CWE-120)
value: irc_mode_channel_update in plugins/irc/irc-mode.c in WeeChat through 2.7 allows remote attackers to cause a denial of service (buffer overflow and application crash) or possibly have unspecified other impact via a malformed IRC message 324 (channel mode).
CWE description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
CVSS v3 base score: 9.8
Published: 2020-02-12T22:15Z
Repository: https://github.com/weechat/weechat
Language: C
Files changed: ChangeLog.adoc, src/plugins/irc/irc-mode.c
Commit date: 2020-02-08 20:24:50 +0100
Commit message: irc: fix crash when receiving a malformed message 324 (channel mode)

Thanks to Stuart Nevans Locke for reporting the issue.

Diff: diff --git a/ChangeLog.adoc b/ChangeLog.adoc
index 2477ac12c..a638dbd15 100644
--- a/ChangeLog.adoc
+++ b/ChangeLog.adoc
@@ -28,10 +28,11 @@ New features::
 
 Bug fixes::
 
   * core: flush stdout/stderr before forking in hook_process function (issue #1441)
   * core: fix evaluation of condition with nested "if" (issue #1434)
+  * irc: fix crash when receiving a malformed message 324 (channel mode)
   * irc: add nick changes in the hotlist (except self nick change)
   * irc: case-insensitive comparison on incoming CTCP command, force upper case on CTCP replies (issue #1439)
   * irc: fix memory leak when the channel topic is changed
   * logger: fix crash when logging is disabled on a buffer and the log file was deleted in the meanwhile, when option logger.file.info_lines is on (issue #1444)
   * relay: update buffers synchronization when buffers are renamed (issue #1428)
diff --git a/src/plugins/irc/irc-mode.c b/src/plugins/irc/irc-mode.c
index 2237a344b..e79f0deb7 100644
--- a/src/plugins/irc/irc-mode.c
+++ b/src/plugins/irc/irc-mode.c
@@ -222,21 +222,24 @@ irc_mode_channel_update (struct t_irc_server *server,
                 }
                 if (ptr_arg)
                     current_arg++;
                 if (pos[0] == chanmode)
                 {
-                    chanmode_found = 1;
-                    if (set_flag == '+')
+                    if (!chanmode_found)
                     {
-                        str_mode[0] = pos[0];
-                        str_mode[1] = '\0';
-                        strcat (new_modes, str_mode);
-                        if (argument)
+                        chanmode_found = 1;
+                        if (set_flag == '+')
                         {
-                            if (new_args[0])
-                                strcat (new_args, " ");
-                            strcat (new_args, argument);
+                            str_mode[0] = pos[0];
+                            str_mode[1] = '\0';
+                            strcat (new_modes, str_mode);
+                            if (argument)
+                            {
+                                if (new_args[0])
+                                    strcat (new_args, " ");
+                                strcat (new_args, argument);
+                            }
                         }
                     }
                 }
                 else
                 {

Vulnerable code:                     chanmode_found = 1;
                    if (set_flag == '+')
                        str_mode[0] = pos[0];
                        str_mode[1] = '\0';
                        strcat (new_modes, str_mode);
                        if (argument)
                            if (new_args[0])
                                strcat (new_args, " ");
                            strcat (new_args, argument);
Fixed code:   * irc: fix crash when receiving a malformed message 324 (channel mode)
                    if (!chanmode_found)
                        chanmode_found = 1;
                        if (set_flag == '+')
                            str_mode[0] = pos[0];
                            str_mode[1] = '\0';
                            strcat (new_modes, str_mode);
                            if (argument)
                            {
                                if (new_args[0])
                                    strcat (new_args, " ");
                                strcat (new_args, argument);
                            }