Compare commits

...

4 Commits

Author SHA1 Message Date
Xavier Roche
9bf741f4b0 htsserver: bound LANG_LIST's lang_str copy by its own size
LANG_LIST bounded its fixed "LANGUAGE_NAME" copy into lang_str[1024] by
buffer_size — the capacity of the *output* buffer, not lang_str's. Harmless
today (the source is a 13-byte literal), but it's the wrong size for that
destination and would become a real overflow if the source ever grew. Bound by
sizeof(lang_str) like the sibling htslang_load call just below it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-06-16 22:18:55 +02:00
Xavier Roche
d9c7ea41e8 Merge pull request #374 from xroche/cleanup/htsserver-bounds
Bound the last pointer-destination string copies in htsserver.c
2026-06-16 22:17:50 +02:00
Xavier Roche
b52b117b90 Bound the last pointer-destination string copies in htsserver.c
Clears htsserver.c's five remaining unbounded strcpybuff/strcatbuff/
strncatbuff pointer-destination sites, the last in the tree, completing the
htssafe pointer-destination migration.

Four are behavior-preserving: each destination's capacity is known at the
call site, so the explicit-size form bounds by the same allocation the raw
copy already relied on (smallserver's POST buffer over buffer_size, the
template name_[1026] scratch over its own size with n already < 1024, the
exact-fit malloc(len+1) lang-key copy).

htslang_load's two writes into its caller buffer were raw strcpy of a
language-name string read from the lang files; a name longer than the
caller's lang_str[1024] would have overflowed. Thread a limit_size through
the (static, internal) signature and bound both writes; the NULL-limit
callers pass 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-06-16 22:13:18 +02:00
Xavier Roche
19d925e6e0 Merge pull request #373 from xroche/ci/cache-git-clang-format
ci: cache pinned tool downloads (git-clang-format, shfmt)
2026-06-16 21:51:12 +02:00

View File

@@ -129,7 +129,8 @@ HTS_UNUSED static int linputsoc_t(T_SOC soc, char *s, int max, int timeout);
HTS_UNUSED static int linput(FILE * fp, char *s, int max);
/* Language files */
HTS_UNUSED static int htslang_load(char *limit_to, const char *apppath);
HTS_UNUSED static int htslang_load(char *limit_to, size_t limit_size,
const char *apppath);
HTS_UNUSED static void conv_printf(const char *from, char *to);
HTS_UNUSED static void LANG_DELETE(void);
HTS_UNUSED static void LANG_INIT(const char *path);
@@ -325,7 +326,7 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
/* Load strings */
htslang_init();
if (!htslang_load(NULL, path)) {
if (!htslang_load(NULL, 0, path)) {
fprintf(stderr, "unable to find lang.def and/or lang/ strings in %s\n",
path);
return 0;
@@ -511,7 +512,7 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
char *s = buffer;
char *e, *f;
strcatbuff(buffer, "&");
strlcatbuff(buffer, "&", buffer_size);
while(s && (e = strchr(s, '=')) && (f = strchr(s, '&'))) {
const char *ua;
String sua = STRING_EMPTY;
@@ -935,7 +936,7 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {
int listDefault = 0;
name[0] = '\0';
strncatbuff(name, str, n);
strlncatbuff(name, str, sizeof(name_), n);
if (strncmp(name, "/*", 2) == 0) {
/* comments */
@@ -1490,7 +1491,7 @@ int smallserver_setkeyarr(const char *key, int id, const char *key2, const char
return coucal_write(NewLangList, tmp, (intptr_t) strdup(value));
}
static int htslang_load(char *limit_to, const char *path) {
static int htslang_load(char *limit_to, size_t limit_size, const char *path) {
const char *hashname;
char catbuff[CATBUFF_SIZE];
@@ -1545,7 +1546,7 @@ static int htslang_load(char *limit_to, const char *path) {
char *const buff = (char *) malloc(len + 1);
if (buff) {
strcpybuff(buff, intkey);
strlcpybuff(buff, intkey, len + 1);
coucal_add(NewLangStrKeys, key, (intptr_t) buff);
}
}
@@ -1568,9 +1569,9 @@ static int htslang_load(char *limit_to, const char *path) {
/* Get only language name */
if (limit_to) {
if (hashname)
strcpybuff(limit_to, hashname);
strlcpybuff(limit_to, hashname, limit_size);
else
strcpybuff(limit_to, "???");
strlcpybuff(limit_to, "???", limit_size);
return 0;
}
@@ -1750,7 +1751,7 @@ static void LANG_INIT(const char *path) {
static int LANG_T(const char *path, int l) {
if (l >= 0) {
QLANG_T(l);
htslang_load(NULL, path);
htslang_load(NULL, 0, path);
}
return QLANG_T(-1); // 0=default (english)
}
@@ -1764,7 +1765,7 @@ static int LANG_SEARCH(const char *path, const char *iso) {
do {
QLANG_T(i);
strcpybuff(lang_str, "LANGUAGE_ISO");
htslang_load(lang_str, path);
htslang_load(lang_str, sizeof(lang_str), path);
if (strfield(iso, lang_str)) {
found = i;
}
@@ -1782,11 +1783,11 @@ static int LANG_LIST(const char *path, char *buffer, size_t buffer_size) {
buffer[0] = '\0';
do {
QLANG_T(i);
strlcpybuff(lang_str, "LANGUAGE_NAME", buffer_size);
htslang_load(lang_str, path);
strlcpybuff(lang_str, "LANGUAGE_NAME", sizeof(lang_str));
htslang_load(lang_str, sizeof(lang_str), path);
if (strlen(lang_str) > 0) {
if (buffer[0])
strcatbuff(buffer, "\n");
strlcatbuff(buffer, "\n", buffer_size);
strlcatbuff(buffer, lang_str, buffer_size);
}
i++;