From 9dd325e29a53234f9bb6eee21b7607140a0f380d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 1 Mar 2026 09:58:43 +0000 Subject: [PATCH] Fix unsafe string ops in CTFSay_Team helpers Replace strcpy/strcat/sprintf with bounds-checked equivalents (Q_strlcpy, Q_strlcat, snprintf) in CTFSay_Team_Location, CTFSay_Team_Armor, and CTFSay_Team_Sight where buffer overflows are possible due to dynamic data or strcat chains. Backported from yquake2remaster commit 16e68994. --- src/g_ctf.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/g_ctf.c b/src/g_ctf.c index 6bce41a..7227763 100644 --- a/src/g_ctf.c +++ b/src/g_ctf.c @@ -2801,7 +2801,7 @@ struct }; static void -CTFSay_Team_Location(edict_t *who, char *buf) +CTFSay_Team_Location(edict_t *who, char *buf, size_t bufsize) { edict_t *what = NULL; edict_t *hot = NULL; @@ -2870,7 +2870,7 @@ CTFSay_Team_Location(edict_t *who, char *buf) if (!hot) { - strcpy(buf, "nowhere"); + Q_strlcpy(buf, "nowhere", bufsize); return; } @@ -2913,14 +2913,14 @@ CTFSay_Team_Location(edict_t *who, char *buf) if ((item = FindItemByClassname(hot->classname)) == NULL) { - strcpy(buf, "nowhere"); + Q_strlcpy(buf, "nowhere", bufsize); return; } /* in water? */ if (who->waterlevel) { - strcpy(buf, "in the water "); + Q_strlcpy(buf, "in the water ", bufsize); } else { @@ -2934,36 +2934,36 @@ CTFSay_Team_Location(edict_t *who, char *buf) { if (v[2] > 0) { - strcat(buf, "above "); + Q_strlcat(buf, "above ", bufsize); } else { - strcat(buf, "below "); + Q_strlcat(buf, "below ", bufsize); } } else { - strcat(buf, "near "); + Q_strlcat(buf, "near ", bufsize); } if (nearteam == CTF_TEAM1) { - strcat(buf, "the red "); + Q_strlcat(buf, "the red ", bufsize); } else if (nearteam == CTF_TEAM2) { - strcat(buf, "the blue "); + Q_strlcat(buf, "the blue ", bufsize); } else { - strcat(buf, "the "); + Q_strlcat(buf, "the ", bufsize); } - strcat(buf, item->pickup_name); + Q_strlcat(buf, item->pickup_name, bufsize); } static void -CTFSay_Team_Armor(edict_t *who, char *buf) +CTFSay_Team_Armor(edict_t *who, char *buf, size_t bufsize) { gitem_t *item; int index, cells; @@ -2979,7 +2979,8 @@ CTFSay_Team_Armor(edict_t *who, char *buf) if (cells) { - sprintf(buf + strlen(buf), "%s with %i cells ", + snprintf(buf + strlen(buf), bufsize - strlen(buf), + "%s with %i cells ", (power_armor_type == POWER_ARMOR_SCREEN) ? "Power Screen" : "Power Shield", cells); } @@ -2995,17 +2996,18 @@ CTFSay_Team_Armor(edict_t *who, char *buf) { if (*buf) { - strcat(buf, "and "); + Q_strlcat(buf, "and ", bufsize); } - sprintf(buf + strlen(buf), "%i units of %s", + snprintf(buf + strlen(buf), bufsize - strlen(buf), + "%i units of %s", who->client->pers.inventory[index], item->pickup_name); } } if (!*buf) { - strcpy(buf, "no armor"); + Q_strlcpy(buf, "no armor", bufsize); } } @@ -3060,7 +3062,7 @@ CTFSay_Team_Weapon(edict_t *who, char *buf) } static void -CTFSay_Team_Sight(edict_t *who, char *buf) +CTFSay_Team_Sight(edict_t *who, char *buf, size_t bufsize) { int i; edict_t *targ; @@ -3097,7 +3099,7 @@ CTFSay_Team_Sight(edict_t *who, char *buf) n++; } - strcpy(s2, targ->client->pers.netname); + Q_strlcpy(s2, targ->client->pers.netname, sizeof(s2)); } if (*s2) @@ -3112,11 +3114,11 @@ CTFSay_Team_Sight(edict_t *who, char *buf) strcat(s, s2); } - strcpy(buf, s); + Q_strlcpy(buf, s, bufsize); } else { - strcpy(buf, "no one"); + Q_strlcpy(buf, "no one", bufsize); } } @@ -3150,7 +3152,7 @@ CTFSay_Team(edict_t *who, char *msg) { case 'l': case 'L': - CTFSay_Team_Location(who, buf); + CTFSay_Team_Location(who, buf, sizeof(buf)); if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) { @@ -3161,7 +3163,7 @@ CTFSay_Team(edict_t *who, char *msg) break; case 'a': case 'A': - CTFSay_Team_Armor(who, buf); + CTFSay_Team_Armor(who, buf, sizeof(buf)); if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) { @@ -3206,7 +3208,7 @@ CTFSay_Team(edict_t *who, char *msg) case 'n': case 'N': - CTFSay_Team_Sight(who, buf); + CTFSay_Team_Sight(who, buf, sizeof(buf)); if (strlen(buf) + (p - outmsg) < sizeof(outmsg) - 2) {