From: Gary Lockyer Date: Tue, 26 May 2026 23:00:30 +0000 (+1200) Subject: lib:util add pointer overflow checks X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e53f7196f45d28689f25a57fa84995eceee4585;p=thirdparty%2Fsamba.git lib:util add pointer overflow checks The wrapping of pointer arithmetic is undefined behaviour. Clang from version 20 onwards will treat checks like: ptr + offset < ptr As always evaluating to true. This commit adds the macros: offset_outside_range ptr_overflow BUG: https://bugzilla.samba.org/show_bug.cgi?id=16092 Signed-off-by: Gary Lockyer Reviewed-by: Stefan Metzmacher Reviewed-by: Volker Lendecke --- diff --git a/lib/util/overflow.h b/lib/util/overflow.h new file mode 100644 index 00000000000..ec9ac179e19 --- /dev/null +++ b/lib/util/overflow.h @@ -0,0 +1,57 @@ +/* + * Unix SMB/CIFS implementation. + * Samba utility functions + * + * Copyright (C) Gary Lockyer 2026 + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see . + */ + +#ifndef __LIB_UTIL_OVERFLOW_H__ +#define __LIB_UTIL_OVERFLOW_H__ + +#include +/** +* Will adding offset to base pointer, result in a pointer that points +* past end, or overflow +* +* @param base The pointer to the start of the range +* @param end The pointer to the end of the range +* @param offset The offset being added to base +* +* @return True resulting pointer is between base and end +* False resulting pointer is after end +*/ +#define offset_outside_range(base, end, offset) \ + (((end) - (base)) < (offset)) + +/** +* Will adding offset to base pointer, result in overflow. +* Pointer arithmetic overflow is undefined behaviour and some compilers +* (i.e. Clang from version 20) will treat an overflow check like the following: +* (ptr + offset) < ptr +* as always evaluating to false +* +* @param ptr The pointer to check +* @param offset The offset being added to ptr +* @param type Type being pointed to by pointer +* needed to cast INTPTR_MAX to the correct type +* +* @return True pointer would over flow +* False pointer would not overflow +*/ +#define ptr_overflow(ptr, offset, type) \ + offset_outside_range((ptr), ((type*)INTPTR_MAX), (offset)) + +#endif diff --git a/lib/util/tests/test_overflow.c b/lib/util/tests/test_overflow.c new file mode 100644 index 00000000000..437374dd9dc --- /dev/null +++ b/lib/util/tests/test_overflow.c @@ -0,0 +1,82 @@ +/* + * cmocka unit tests for the overflow macros + * + * Copyright (C) Gary Lockyer 2026 + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see . + * + */ + +/* + * from cmocka.c: + * These headers or their equivalents should be included prior to + * including + * this header file. + * + * #include + * #include + * #include + * + * This allows test applications to use custom definitions of C standard + * library functions and types. + * + */ +#include +#include +#include +#include + + +#include "lib/util/overflow.h" + +static void test_ptr_overflow_true(void **state) +{ + char *ptr = (char *)INTPTR_MAX; + assert_true(ptr_overflow(ptr, 1, char)); +} + +static void test_ptr_overflow_false(void **state) +{ + char *ptr = (char *)(INTPTR_MAX- 1); + assert_false(ptr_overflow(ptr, 1, char)); +} + +static void test_outside_range_false(void **state) +{ + char base[] = "1234"; + char *end = base + 5; + assert_false(offset_outside_range(base, end, 5)); +} + +static void test_outside_range_true(void **state) +{ + char base[] = "1234"; + char *end = base + 5; + assert_true(offset_outside_range(base, end, 6)); +} + +int main(int argc, const char **argv) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test( test_ptr_overflow_true), + cmocka_unit_test( test_ptr_overflow_false), + cmocka_unit_test( test_outside_range_false), + cmocka_unit_test( test_outside_range_true), + }; + + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + + return cmocka_run_group_tests(tests, NULL, NULL); + +} diff --git a/lib/util/wscript_build b/lib/util/wscript_build index 9b43d05960b..549a58701cb 100644 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -405,6 +405,12 @@ else: local_include=False, for_selftest=True) + bld.SAMBA_BINARY('test_overflow', + source='tests/test_overflow.c', + deps='cmocka', + local_include=False, + for_selftest=True) + bld.SAMBA_BINARY('test_s4_logging', source='tests/test_logging.c', deps=' '.join(['CMDLINE_S4',