From ec7090873363ae92647d3b597524476c404664ff Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 22 Oct 2026 15:11:23 +0200 Subject: [PATCH] Check relative path limits and binding failures without truncation --- src/media_delivery/media_index.c | 6 ++++-- tests/test_media_index_regressions.c | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/media_delivery/media_index.c b/src/media_delivery/media_index.c index 495471c7..1d2fe406 100644 --- a/src/media_delivery/media_index.c +++ b/src/media_delivery/media_index.c @@ -66,13 +66,15 @@ static int mi_location_valid(const char* location) { } int media_index_path(const char* base, const char* location, char path[MEDIA_PATH_MAX]) { - char clean[MEDIA_BASE_MAX]; + char clean[MEDIA_BASE_MAX], full[MEDIA_PATH_MAX]; if (!path) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index path without output"); return -1; } if (mi_clean_path(base, clean, sizeof(clean)) || mi_location_valid(location)) return -1; - int size = snprintf(path, MEDIA_PATH_MAX, "%s%s%s", clean, clean[strlen(clean) - 1] == '/' ? "" : "/", location); + int size = !strcmp(clean, ".") ? snprintf(full, sizeof(full), "%s", location) + : snprintf(full, sizeof(full), "%s%s%s", clean, clean[strlen(clean) - 1] == '/' ? "" : "/", location); if (size >= MEDIA_PATH_MAX || size < 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media_index joined path too long base=%s location=%s", clean, location); return -1; } + memcpy(path, full, (size_t)size + 1); return 0; } diff --git a/tests/test_media_index_regressions.c b/tests/test_media_index_regressions.c index f24c9be5..b0ef46c4 100644 --- a/tests/test_media_index_regressions.c +++ b/tests/test_media_index_regressions.c @@ -59,6 +59,9 @@ static void paths(void) { assert(media_index_path(root, "a//file", path) == -1 && media_index_path(root, "a/./file", path) == -1); assert(media_index_path(root, "C:/file", path) == -1 && media_index_path(root, "a\\file", path) == -1); memset(relative, 'a', sizeof(relative)); relative[sizeof(relative) - 1] = 0; + assert(!media_index_path(".", relative, path) && strlen(path) == MEDIA_PATH_MAX - 1); + assert(!media_index_location(path, ".", relative) && strlen(relative) == MEDIA_PATH_MAX - 1); + assert(!media_index_path(".", relative, relative) && strlen(relative) == MEDIA_PATH_MAX - 1); assert(media_index_path("/", relative, path) == -1); relative[sizeof(relative) - 2] = 0; assert(!media_index_path("/", relative, path) && strlen(path) == MEDIA_PATH_MAX - 1); @@ -117,6 +120,12 @@ static void transactions(void) { assert(scalar(db, "SELECT count(*) FROM media_files WHERE node_sign!=zeroblob(64)") == 2); assert(media_index_register_downloaded(db, result.media_id, ids, result.content_hash, "conflict", "wrong", 1, 14, 7, 0, 0) == -1); assert(scalar(db, "SELECT count(*) FROM media_files WHERE chat_id='1'") == 2); + sql(db, "DELETE FROM media_files"); + char long_path[MEDIA_PATH_MAX], relative[301]; memset(relative, 'x', sizeof(relative) - 1); relative[300] = 0; + assert(!media_index_path(root, relative, long_path)); + int previous_limit = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 200); + assert(commit(db, "1", long_path) == -1 && !scalar(db, "SELECT count(*) FROM media_files")); + sqlite3_limit(db, SQLITE_LIMIT_LENGTH, previous_limit); result.num_blocks = INT_MAX; assert(commit(db, "1", path) == -1); result.num_blocks = 2; sqlite3_close(db);