From 899d19606250fa3f341ce0bca1480351ede37211 Mon Sep 17 00:00:00 2001 From: Aizal Khan Date: Thu, 2 Jul 2026 14:13:32 +0530 Subject: [PATCH] fix stack overflow in ExpandLinks path component parsing Signed-off-by: Aizal Khan --- libpromises/files_links.c | 13 ++++++-- tests/unit/Makefile.am | 4 +++ tests/unit/files_links_test.c | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 tests/unit/files_links_test.c diff --git a/libpromises/files_links.c b/libpromises/files_links.c index 42752b6978..62fd9b58a2 100644 --- a/libpromises/files_links.c +++ b/libpromises/files_links.c @@ -707,8 +707,17 @@ bool ExpandLinks(char *dest, const char *from, int level, int max_level) continue; } - sscanf(sp, "%[^/]", node); - sp += strlen(node); + size_t node_len = strcspn(sp, "/"); + if (node_len >= sizeof(node)) + { + Log(LOG_LEVEL_ERR, + "Internal limit reached in ExpandLinks()," + " path component too long: '%s'", sp); + return false; + } + memcpy(node, sp, node_len); + node[node_len] = '\0'; + sp += node_len; if (*sp == '\0') { diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 642d2091f1..b59d378b28 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -111,6 +111,7 @@ check_PROGRAMS = \ package_versions_compare_test \ files_lib_test \ files_copy_test \ + files_links_test \ parsemode_test \ parser_test \ passopenfile_test \ @@ -287,6 +288,9 @@ package_versions_compare_test_LDADD = ../../libpromises/libpromises.la \ files_copy_test_SOURCES = files_copy_test.c files_copy_test_LDADD = libtest.la ../../libpromises/libpromises.la +files_links_test_SOURCES = files_links_test.c +files_links_test_LDADD = libtest.la ../../libpromises/libpromises.la + sort_test_SOURCES = sort_test.c sort_test_LDADD = libtest.la ../../libpromises/libpromises.la diff --git a/tests/unit/files_links_test.c b/tests/unit/files_links_test.c new file mode 100644 index 0000000000..9b18ddde5d --- /dev/null +++ b/tests/unit/files_links_test.c @@ -0,0 +1,56 @@ +/* + Copyright 2024 Northern.tech AS + + This file is part of CFEngine 3 - written and maintained by Northern.tech AS. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; version 3. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + + To the extent this program is licensed as part of the Enterprise + versions of CFEngine, the applicable Commercial Open Source License + (COSL) may apply to this file if you as a licensee so wish it. See + included file COSL.txt. +*/ + +#include + +#include +#include /* ExpandLinks */ + +/* A single path component longer than the internal node buffer + * (CF_MAXLINKSIZE) overflowed the stack in ExpandLinks(): the parse into + * 'node' ran before any lstat(), so a symlink target with a long slash-free + * component smashed the stack. It must bail out instead. */ +static void test_expand_links_long_component(void) +{ + char dest[CF_BUFSIZE]; + + char from[1024]; + from[0] = '/'; + memset(from + 1, 'a', sizeof(from) - 2); + from[sizeof(from) - 1] = '\0'; + + bool ret = ExpandLinks(dest, from, 0, CF_MAXLINKLEVEL); + assert_false(ret); +} + +int main() +{ + PRINT_TEST_BANNER(); + + const UnitTest tests[] = { + unit_test(test_expand_links_long_component), + }; + + return run_tests(tests); +}