CVE-2020-9760 (published 2020-03-23T16:15Z)

An issue was discovered in WeeChat before 2.7.1 (0.3.4 to 2.7 are affected). When a new IRC message 005 is received with longer nick prefixes, a buffer overflow and possibly a crash can happen when a new mode is set for a nick.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-120
cwe_name: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
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.
extended_description: A buffer overflow condition exists when a product attempts to put more data in a buffer than it can hold, or when it attempts to put data in a memory area outside of the boundaries of a buffer. The simplest type of error, and the most common cause of buffer overflows, is the "classic" case in which the product copies the buffer without restricting how much is copied. Other variants exist, but the existence of a classic overflow strongly suggests that the programmer is not considering even the most basic of security protections.
         

Fix information:
repo_url: https://github.com/weechat/weechat
commit_details: repo_url: https://github.com/weechat/weechat
author: Sébastien Helleu
author_date: 2020-02-09 20:04:45+01:00
msg: irc: fix crash when a new message 005 is received with longer nick prefixes

Thanks to Stuart Nevans Locke for reporting the issue.
repository: repo_url: https://github.com/weechat/weechat
repo_name: weechat/weechat
description: The extensible chat client.
repo_language: C
owner: weechat
file_changes: filename: ChangeLog.adoc
change_type: ModificationType.MODIFY
diff: @@ -31,6 +31,7 @@ Bug fixes::
   * core: fix memory leak in completion
   * 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 a new message 005 is received with longer nick prefixes
   * 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)

programming_language: Markdown
filename: irc-nick.c
change_type: ModificationType.MODIFY
diff: @@ -643,6 +643,53 @@ irc_nick_set_mode (struct t_irc_server *server, struct t_irc_channel *channel,
     }
 }
 
+/*
+ * Reallocates the "prefixes" string in all nicks of all channels on the server
+ * (after 005 has been received).
+ */
+
+void
+irc_nick_realloc_prefixes (struct t_irc_server *server,
+                           int old_length, int new_length)
+{
+    struct t_irc_channel *ptr_channel;
+    struct t_irc_nick *ptr_nick;
+    char *new_prefixes;
+
+    for (ptr_channel = server->channels; ptr_channel;
+         ptr_channel = ptr_channel->next_channel)
+    {
+        for (ptr_nick = ptr_channel->nicks; ptr_nick;
+             ptr_nick = ptr_nick->next_nick)
+        {
+            if (ptr_nick->prefixes)
+            {
+                new_prefixes = realloc (ptr_nick->prefixes, new_length + 1);
+                if (new_prefixes)
+                {
+                    ptr_nick->prefixes = new_prefixes;
+                    if (new_length > old_length)
+                    {
+                        memset (ptr_nick->prefixes + old_length,
+                                ' ',
+                                new_length - old_length);
+                    }
+                    ptr_nick->prefixes[new_length] = '\0';
+                }
+            }
+            else
+            {
+                ptr_nick->prefixes = malloc (new_length + 1);
+                if (ptr_nick->prefixes)
+                {
+                    memset (ptr_nick->prefixes, ' ', new_length);
+                    ptr_nick->prefixes[new_length] = '\0';
+                }
+            }
+        }
+    }
+}
+
 /*
  * Removes a nick from a channel.
  */

programming_language: C
filename: irc-nick.h
change_type: ModificationType.MODIFY
diff: @@ -74,6 +74,8 @@ extern void irc_nick_change (struct t_irc_server *server,
 extern void irc_nick_set_mode (struct t_irc_server *server,
                                struct t_irc_channel *channel,
                                struct t_irc_nick *nick, int set, char mode);
+extern void irc_nick_realloc_prefixes (struct t_irc_server *server,
+                                       int old_length, int new_length);
 extern void irc_nick_free (struct t_irc_server *server,
                            struct t_irc_channel *channel,
                            struct t_irc_nick *nick);

programming_language: C
filename: irc-server.c
change_type: ModificationType.MODIFY
diff: @@ -988,11 +988,14 @@ irc_server_set_prefix_modes_chars (struct t_irc_server *server,
                                    const char *prefix)
 {
     char *pos;
-    int i, length_modes, length_chars;
+    int i, old_length_chars, length_modes, length_chars;
 
     if (!server || !prefix)
         return;
 
+    old_length_chars = (server->prefix_chars) ?
+        strlen (server->prefix_chars) : 0;
+
     /* free previous values */
     if (server->prefix_modes)
     {
@@ -1032,6 +1035,10 @@ irc_server_set_prefix_modes_chars (struct t_irc_server *server,
             }
         }
     }
+
+    length_chars = (server->prefix_chars) ? strlen (server->prefix_chars) : 0;
+    if (server->prefix_chars && (length_chars != old_length_chars))
+        irc_nick_realloc_prefixes (server, old_length_chars, length_chars);
 }
 
 /*

programming_language: C