short-chain strlcpy bound fixes via strlcpy_append

Apply strlcpy_append (commit 78c52ab) to seven sites flagged
in the strlcpy-misuse audit, all sharing the same shape:

   _len = strlcpy(dst, src1, sizeof(dst));
   dst[_len]   = c1;
   dst[++_len] = c2;
   ...
   strlcpy(dst + _len, src2, sizeof(dst) - _len);

None of these had a bound on _len.  When src1 was longer
than sizeof(dst) - 1, strlcpy returned strlen(src1) >=
sizeof(dst) and:
  - the dst[_len], dst[++_len], ... character writes ran
    off the end of dst (stack buffer overflow);
  - the trailing strlcpy got len - _len which underflowed
    size_t, producing an unbounded copy.

Sites:

menu/drivers/materialui.c:8090 - "Draw message box".
   dst is msg[NAME_MAX_LENGTH] which is 128 on Xbox1, 3DS,
   PSP, PS2, GameCube, Wii, WiiU, PS3, Emscripten and 256
   elsewhere.  src1 is menu_st->input_dialog_kb_label[256]
   (always 256 regardless of platform).  On the small-
   NAME_MAX_LENGTH platforms a long label drove _len up to
   ~255 and the chain wrote up to 127 bytes past the stack
   frame.  Reachable from any input dialog.

tasks/task_http.c:495 and tasks/task_http_emscripten.c:312 -
   download status string.  dst is tmp[NAME_MAX_LENGTH];
   src1 is the localized "Downloading" string.  Same
   primitive on small-NAME_MAX_LENGTH platforms when a
   translation pushed the prefix close to the cap.

menu/cbs/menu_cbs_sublabel.c:2164 - core backup CRC sublabel.
   The chain wrote 8 character bytes ("00000000") plus a NUL
   after the localized "Backup CRC: " prefix.  dst is the
   caller's s/len; if a translation pushed the prefix close
   to len, the 9 byte writes ran past the caller's buffer.

steam/steam.c:449/471/493 - rich-presence content strings.
   Three near-identical cases (CONTENT_SYSTEM, CONTENT_CORE,
   CONTENT_SYSTEM_CORE).  Each builds "LABEL (CONTENT)" or
   "LABEL (N/A)" with hand-unrolled writes of " (", "N/A",
   "/", "A", ")", "\0" at offsets _len + N.  dst is
   content[PATH_MAX_LENGTH] (512 on small platforms, 4096
   elsewhere) and the per-character write offsets reached
   _len + 12 on the SYSTEM_CORE variant; long labels OOB-
   wrote up to 12 bytes past content.

Replace each chain with a sequence of strlcpy_append calls
on a single rolling cursor, with the helper handling the
bound check at every step.  No functional change at the
buffer-fits-comfortably end; on small buffers the new code
truncates cleanly instead of stack-overflowing.

No new tests -- the strlcpy_append regression test from
commit 78c52ab covers the helper's contract; these are
just additional users.
This commit is contained in:
U-DESKTOP-SPFP6AQ\twistedtechre committed 2026-04-28 07:04:30 +02:00
1 parent 78c52ab36e
commit e4462428e4
5 files changed
+44 -93

No files matched your search

+5 -16
View File
@@ -2160,25 +2160,14 @@ static int action_bind_sublabel_core_backup_entry(
const char *crc = list->list[i].alt
? list->list[i].alt
: list->list[i].path;
/* Set sublabel prefix */
size_t _len = strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_BACKUP_CRC), len);
size_t _len = 0;
strlcpy_append(s, len, &_len,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_BACKUP_CRC));
/* Add CRC string */
if (!crc || !*crc)
{
s[ _len] = '0';
s[++_len] = '0';
s[++_len] = '0';
s[++_len] = '0';
s[++_len] = '0';
s[++_len] = '0';
s[++_len] = '0';
s[++_len] = '0';
s[++_len] = '\0';
}
strlcpy_append(s, len, &_len, "00000000");
else
strlcpy(s + _len, crc, len - _len);
strlcpy_append(s, len, &_len, crc);
return 1;
}
+4 -6
View File
@@ -8087,12 +8087,10 @@ static void materialui_frame(void *data, video_frame_info_t *video_info)
NULL);
/* Draw message box */
_len = strlcpy(msg, label, sizeof(msg));
msg[ _len] = '\n';
msg[++_len] = '\0';
strlcpy(msg + _len,
str,
sizeof(msg) - _len);
_len = 0;
strlcpy_append(msg, sizeof(msg), &_len, label);
strlcpy_append(msg, sizeof(msg), &_len, "\n");
strlcpy_append(msg, sizeof(msg), &_len, str);
materialui_render_messagebox(mui,
p_disp,
userdata, video_width, video_height,
+25 -60
View File
@@ -446,82 +446,47 @@ void steam_update_presence(enum presence presence, bool force)
}
break;
case STEAM_RICH_PRESENCE_FORMAT_CONTENT_SYSTEM:
_len = strlcpy(content, label, sizeof(content));
content[_len ] = ' ';
content[_len+1] = '(';
content[_len+2] = '\0';
_len = 0;
strlcpy_append(content, sizeof(content), &_len, label);
strlcpy_append(content, sizeof(content), &_len, " (");
if (core_info)
{
_len += 2;
_len += strlcpy(content + _len, core_info->systemname,
sizeof(content) - _len);
content[_len ] = ')';
content[_len+1] = '\0';
strlcpy_append(content, sizeof(content), &_len,
core_info->systemname);
strlcpy_append(content, sizeof(content), &_len, ")");
}
else
{
content[_len+2] = 'N';
content[_len+3] = '/';
content[_len+4] = 'A';
content[_len+5] = ')';
content[_len+6] = '\0';
}
strlcpy_append(content, sizeof(content), &_len, "N/A)");
break;
case STEAM_RICH_PRESENCE_FORMAT_CONTENT_CORE:
_len = strlcpy(content, label, sizeof(content));
content[_len ] = ' ';
content[_len+1] = '(';
content[_len+2] = '\0';
_len = 0;
strlcpy_append(content, sizeof(content), &_len, label);
strlcpy_append(content, sizeof(content), &_len, " (");
if (core_info)
{
_len += 2;
_len += strlcpy(content + _len, core_info->core_name,
sizeof(content) - _len);
content[_len ] = ')';
content[_len+1] = '\0';
strlcpy_append(content, sizeof(content), &_len,
core_info->core_name);
strlcpy_append(content, sizeof(content), &_len, ")");
}
else
{
content[_len+2] = 'N';
content[_len+3] = '/';
content[_len+4] = 'A';
content[_len+5] = ')';
content[_len+6] = '\0';
}
strlcpy_append(content, sizeof(content), &_len, "N/A)");
break;
case STEAM_RICH_PRESENCE_FORMAT_CONTENT_SYSTEM_CORE:
_len = strlcpy(content, label, sizeof(content));
content[_len ] = ' ';
content[_len+1] = '(';
content[_len+2] = '\0';
_len = 0;
strlcpy_append(content, sizeof(content), &_len, label);
strlcpy_append(content, sizeof(content), &_len, " (");
if (core_info)
{
_len += 2;
_len += strlcpy(content + _len, core_info->systemname,
sizeof(content) - _len);
content[_len ] = ' ';
content[_len+1] = '-';
content[_len+2] = ' ';
_len += 3;
_len += strlcpy(content + _len, core_info->core_name,
sizeof(content) - _len);
content[_len ] = ')';
content[_len+1] = '\0';
strlcpy_append(content, sizeof(content), &_len,
core_info->systemname);
strlcpy_append(content, sizeof(content), &_len, " - ");
strlcpy_append(content, sizeof(content), &_len,
core_info->core_name);
strlcpy_append(content, sizeof(content), &_len, ")");
}
else
{
content[_len+2] = 'N';
content[_len+3] = '/';
content[_len+4] = 'A';
content[_len+5] = ' ';
content[_len+6] = '-';
content[_len+7] = ' ';
content[_len+8] = 'N';
content[_len+9] = '/';
content[_len+10] = 'A';
content[_len+11] = ')';
content[_len+12] = '\0';
}
strlcpy_append(content, sizeof(content), &_len,
"N/A - N/A)");
break;
case STEAM_RICH_PRESENCE_FORMAT_NONE:
default:
+5 -6
View File
@@ -491,17 +491,16 @@ void* task_push_http_transfer_file(const char* url, bool mute,
s = transfer_data->path;
else
s = url;
_len = strlcpy(tmp, msg_hash_to_str(MSG_DOWNLOADING), sizeof(tmp));
tmp[ _len] = ':';
tmp[++_len] = ' ';
tmp[++_len] = '\0';
_len = 0;
strlcpy_append(tmp, sizeof(tmp), &_len,
msg_hash_to_str(MSG_DOWNLOADING));
strlcpy_append(tmp, sizeof(tmp), &_len, ": ");
if (string_ends_with_size(s, ".index",
strlen(s), STRLEN_CONST(".index")))
s = msg_hash_to_str(MSG_INDEX_FILE);
strlcpy(tmp + _len, s, sizeof(tmp) - _len);
strlcpy_append(tmp, sizeof(tmp), &_len, s);
/* should be using type but some callers now rely on type being ignored */
return task_push_http_transfer_generic_titled(
+5 -5
View File
@@ -308,16 +308,16 @@ void* task_push_http_transfer_file(const char* url, bool mute,
s = transfer_data->path;
else
s = url;
_len = strlcpy(tmp, msg_hash_to_str(MSG_DOWNLOADING), sizeof(tmp));
tmp[ _len] = ' ';
tmp[++_len] = '\0';
_len = 0;
strlcpy_append(tmp, sizeof(tmp), &_len,
msg_hash_to_str(MSG_DOWNLOADING));
strlcpy_append(tmp, sizeof(tmp), &_len, " ");
if (string_ends_with_size(s, ".index",
strlen(s), STRLEN_CONST(".index")))
s = msg_hash_to_str(MSG_INDEX_FILE);
strlcpy(tmp + _len, s, sizeof(tmp) - _len);
strlcpy_append(tmp, sizeof(tmp), &_len, s);
t->title = strdup(tmp);
return t;