diff --git a/src/config_updater.c b/src/config_updater.c index 698e768b..6841587a 100644 --- a/src/config_updater.c +++ b/src/config_updater.c @@ -106,6 +106,8 @@ static int config_edit(const char *text, size_t length, const struct config_fiel const char *eol = nl && nl > text && nl[-1] == '\r' ? "\r\n" : "\n"; int section = CFG_OTHER_SECTION; for (size_t pos = 0;;) { + /* Запас покрывает вставки полей и строки: strbuf не должен вырасти до 2^32 байтов. */ + if (output->len > UINT32_MAX / 2 - 16384) return -1; for (int s = CFG_GLOBAL_SECTION; s < CFG_SECTION_COUNT; s++) { if (ends[s] == pos && config_insert_missing(output, fields, s, 1, eol)) return -1; } @@ -128,6 +130,7 @@ static int config_edit(const char *text, size_t length, const struct config_fiel } else if (strbuf_addf(output, "%.*s", (int)(end - pos), text + pos) < 0) return -1; pos = end; } + if (output->len > UINT32_MAX / 2 - 16384) return -1; for (int s = CFG_GLOBAL_SECTION; s < CFG_SECTION_COUNT; s++) { if (ends[s] == SIZE_MAX && config_insert_missing(output, fields, s, 0, eol)) return -1; } diff --git a/tests/test_config_updater.c b/tests/test_config_updater.c index 402799b5..7c275f67 100644 --- a/tests/test_config_updater.c +++ b/tests/test_config_updater.c @@ -193,9 +193,12 @@ static void test_identity_and_text(void) { "[global]\r\nmy_public_key=still_bad\r\nmy_node_id=bad\r\n", private_hex); write_text(text); assert(!chmod(path, 0640)); + struct stat ownership; + assert(!stat(path, &ownership)); assert(!config_ensure_keys_and_node_id(path)); check_identity(private_hex); assert(!stat(path, &info) && (info.st_mode & 0777) == 0640); + assert(info.st_uid == ownership.st_uid && info.st_gid == ownership.st_gid); read_text(text, sizeof(text)); assert(strstr(text, "[gui]\r\nmy_private_key=foreign\r\n")); assert(strstr(text, "[global_extra]\r\nmy_public_key=untouched\r\n")); @@ -218,6 +221,11 @@ static void test_identity_and_text(void) { assert(!strcmp(before, text)); assert(!stat(path, &info) && info.st_ino == old_info.st_ino); + snprintf(text, sizeof(text), "[global]\nmy_private_key=%064d\n[GLOBAL]\nmy_private_key = %s\n", 0, private_hex); + write_text(text); + assert(!config_ensure_keys_and_node_id(path)); + check_identity(private_hex); + write_text("[global]\nmy_private_key=bad\nmy_private_key=still_bad\n"); assert(!config_ensure_keys_and_node_id(path)); check_identity(NULL); @@ -256,6 +264,22 @@ static void test_reality_and_validation(void) { read_text(text, sizeof(text)); assert(!strcmp(before, text)); + snprintf(text, sizeof(text), "[global]\nmy_private_key=%s\n[reality]\nenabled=1\nprivate_key=%s\n" + "short_ids=bad\n[REALITY]\nshort_ids = 0102030405060708\n", private_hex, private_hex); + write_text(text); + assert(!config_ensure_keys_and_node_id(path)); + config = parse_config(path); + assert(config && config->global.reality.short_id_count == 1); + assert(!strcasecmp(config->global.my_private_key_hex, private_hex)); + free_config(config); + size_t saved_length = read_text(before, sizeof(before)); + assert(saved_length + 20 < sizeof(before)); + strcat(before, "enabled=0\nshort_ids=bad\nprivate_key=bad\n"); + write_text(before); + assert(!config_ensure_keys_and_node_id(path)); + read_text(text, sizeof(text)); + assert(!strcmp(before, text)); + const char *bad_lists[] = {"0102030405060708,bad", "0102030405060708,", ",0102030405060708", "0102030405060708,,0102030405060708"}; for (size_t i = 0; i < sizeof(bad_lists) / sizeof(*bad_lists); i++) { snprintf(text, sizeof(text), "[reality]\nshort_ids=%s\n", bad_lists[i]);