From d4a4744be4607c64225f8b64899aa402782aceb4 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 3 May 2022 14:38:33 +0100 Subject: [PATCH] 10.68: Annocheck: Add more glibc exceptions --- annobin-global.h | 2 +- annocheck/hardened.c | 59 +++++++++++++++++++++------ annocheck/libannocheck.h | 2 +- doc/annobin.info | 86 +++++++++++++++++++++------------------- doc/annobin.texi | 26 ++++++++---- 5 files changed, 112 insertions(+), 63 deletions(-) diff --git a/annobin-global.h b/annobin-global.h index 36066ec..64516c7 100644 --- a/annobin-global.h +++ b/annobin-global.h @@ -23,7 +23,7 @@ extern "C" { NB/ Keep this value in sync with libannochck_version defined in annocheck/libannocheck.h. */ -#define ANNOBIN_VERSION 1067 +#define ANNOBIN_VERSION 1068 /* The version of the annotation specification supported. */ #define SPEC_VERSION 3 diff --git a/annocheck/hardened.c b/annocheck/hardened.c index 810ec98..45e783d 100644 --- a/annocheck/hardened.c +++ b/annocheck/hardened.c @@ -1176,6 +1176,24 @@ is_special_glibc_binary (const char * path) { int i; + /* The contents of static glibc libraries should be ignored. */ + if (strchr (path, ':')) + { + static const char * known_glibc_libraries [] = + { + "libBrokenLocale.a", + "libc.a:", + "libc_nonshared.a:", + "libm-2.34.a:", + "libmvec.a:", + "libresolv.a:" + }; + + for (i = ARRAY_SIZE (known_glibc_libraries); i--;) + if (strstr (path, known_glibc_libraries[i]) != NULL) + return true; + } + /* If we are testing an uninstalled rpm then the paths will start with "." so skip this. */ if (path[0] == '.') @@ -1213,7 +1231,7 @@ is_special_glibc_binary (const char * path) path += len; break; } - /* Do not abort this loop if res > 0/ + /* Do not abort this loop if res > 0 We can have a file like /usr/lib64/libmcheck.a which will not match /usr/lib64/gconv but which should match /usr/lib64. */ } @@ -1510,8 +1528,10 @@ is_special_glibc_binary (const char * path) "libBrokenLocale-2.28.so", "libBrokenLocale.so.1", "libSegFault.so", + "libanl.so.1", "libc.so.6", "libc_malloc_debug.so.0", + "libdl.so.2", "libg.a:dummy.o", "libm.so.6", "libmcheck.a", @@ -1523,10 +1543,12 @@ is_special_glibc_binary (const char * path) "libnss_compat.so.2", "libpcprofile.so", "libpthread-2.28.so", + "libpthread.so.0", "libresolv-2.28.so", "libresolv.so.2", "librt.so.1", "libthread_db.so.1", + "libutil.so.1", "locale", "localedef", "makedb", @@ -1979,6 +2001,7 @@ skip_fortify_checks_for_function (annocheck_data * data, enum test_index check, "_nss_files_sethostent", "_start", "abort", + "atexit", "blacklist_store_name", "buffer_free", "cabsf128", @@ -4124,19 +4147,18 @@ interesting_seg (annocheck_data * data, if (disabled) return false; - if (! skip_test (TEST_RWX_SEG)) + switch (seg->phdr->p_type) { - if ((seg->phdr->p_flags & (PF_X | PF_W | PF_R)) == (PF_X | PF_W | PF_R)) + case PT_TLS: + if (! skip_test (TEST_RWX_SEG) + && seg->phdr->p_memsz > 0 + && (seg->phdr->p_flags & PF_X)) { - /* Object files should not have segments. */ - assert (! is_object_file ()); - fail (data, TEST_RWX_SEG, SOURCE_SEGMENT_HEADERS, "segment has Read, Write and eXecute flags set"); - einfo (VERBOSE2, "RWX segment number: %d", seg->number); + fail (data, TEST_RWX_SEG, SOURCE_SEGMENT_HEADERS, "TLS segment has eXecute flag set"); + einfo (VERBOSE2, "TLS segment number: %d", seg->number); } - } - - switch (seg->phdr->p_type) - { + break; + case PT_INTERP: per_file.has_program_interpreter = true; break; @@ -4154,6 +4176,7 @@ interesting_seg (annocheck_data * data, fail (data, TEST_GNU_STACK, SOURCE_SEGMENT_HEADERS, "the GNU stack segment has execute permission"); else if ((seg->phdr->p_flags & PF_X) == 0) pass (data, TEST_GNU_STACK, SOURCE_SEGMENT_HEADERS, "stack segment exists with the correct permissions"); + /* FIXME: Check for multiple PT_GNU_STACK segments ? */ } break; @@ -4172,6 +4195,18 @@ interesting_seg (annocheck_data * data, return supports_property_notes (per_file.e_machine); case PT_LOAD: + if (! skip_test (TEST_RWX_SEG)) + { + if (seg->phdr->p_memsz > 0 + && (seg->phdr->p_flags & (PF_X | PF_W | PF_R)) == (PF_X | PF_W | PF_R)) + { + /* Object files should not have segments. */ + assert (! is_object_file ()); + fail (data, TEST_RWX_SEG, SOURCE_SEGMENT_HEADERS, "segment has Read, Write and eXecute flags set"); + einfo (VERBOSE2, "RWX segment number: %d", seg->number); + } + } + /* If we are checking the entry point instruction then we need to load the segment. We check segments rather than sections because executables do not have to have sections. */ @@ -5074,7 +5109,7 @@ finish (annocheck_data * data) else if (is_special_glibc_binary (data->full_filename)) skip (data, i, SOURCE_FINAL_SCAN, "glibc binaries not compiled with LTO"); else - maybe (data, i, SOURCE_FINAL_SCAN, "no indication that LTO was used"); + info (data, i, SOURCE_FINAL_SCAN, "no indication that LTO was used"); break; case TEST_PIE: diff --git a/annocheck/libannocheck.h b/annocheck/libannocheck.h index 87c409b..64bbccb 100644 --- a/annocheck/libannocheck.h +++ b/annocheck/libannocheck.h @@ -18,7 +18,7 @@ extern "C" { /* NB/ Keep this value in sync with ANNOBIN_VERSION defined in annobin-global.h. */ -const unsigned int libannocheck_version = 1067; +const unsigned int libannocheck_version = 1068; typedef enum libannocheck_error { diff --git a/doc/annobin.info b/doc/annobin.info index eaea78b..eade2b3 100644 --- a/doc/annobin.info +++ b/doc/annobin.info @@ -1701,13 +1701,17 @@ File: annobin.info, Node: Test rwx seg, Next: Test short enums, Prev: Test ru Example: FAIL: rwx-seg test because segment has Read, Write and eXecute flags set - This test checks that the file does not have any segments that have -all three of the READ, WRITE and EXECUTE permissions. Code segments -should have read and execute permissions, but they should not be -writable as otherwise an attacker can overwrite the code. Data segments -should have read permission, and possibly write permission as well, but -never execute permission as otherwise an attacker might be able to -create their own code in a data area. + This test checks that the file does not have any segments that are + 1. have all three of the READ, WRITE and EXECUTE permissions. + 2. have a non-zero size + 3. are resident in memory when the program runs + 4. do not have an architecture/OS specific type + + Code segments should have read and execute permissions, but they +should not be writable as otherwise an attacker can overwrite the code. +Data segments should have read permission, and possibly write permission +as well, but never execute permission as otherwise an attacker might be +able to create their own code in a data area. The linker will normally never create a binary file with a segment with all three permissions, but it is possible to force it to do so by @@ -3565,40 +3569,40 @@ Node: Test production64729 Node: Test property note65542 Node: Test run path68019 Node: Test rwx seg70240 -Node: Test short enums71512 -Node: Test stack clash72529 -Node: Test stack prot73990 -Node: Test stack realign75322 -Node: Test textrel76592 -Node: Test threads77849 -Node: Test unicode78664 -Node: Test warnings80155 -Node: Test writable got80990 -Node: Hardened Command Line Options82276 -Node: Waiving Hardened Results87716 -Node: Notes89662 -Node: Size90298 -Node: Timing92667 -Node: Libannocheck93306 -Node: libannocheck_init95245 -Node: libannocheck_finish96167 -Node: libannocheck_get_version96715 -Node: libannocheck_get_error_message97124 -Node: libannocheck_get_known_tests97764 -Node: libannocheck_enable_all_tests98930 -Node: libannocheck_disable_all_tests99409 -Node: libannocheck_enable_test99965 -Node: libannocheck_disable_test100633 -Node: libannocheck_enable_profile101302 -Node: libannocheck_get_known_profiles101824 -Node: libannocheck_run_tests102527 -Node: Configure Options103372 -Node: Legacy Scripts105714 -Node: Who Built Me106489 -Node: ABI Checking109249 -Node: Hardening Checks111365 -Node: Checking Archives115451 -Node: GNU FDL117872 +Node: Test short enums71649 +Node: Test stack clash72666 +Node: Test stack prot74127 +Node: Test stack realign75459 +Node: Test textrel76729 +Node: Test threads77986 +Node: Test unicode78801 +Node: Test warnings80292 +Node: Test writable got81127 +Node: Hardened Command Line Options82413 +Node: Waiving Hardened Results87853 +Node: Notes89799 +Node: Size90435 +Node: Timing92804 +Node: Libannocheck93443 +Node: libannocheck_init95382 +Node: libannocheck_finish96304 +Node: libannocheck_get_version96852 +Node: libannocheck_get_error_message97261 +Node: libannocheck_get_known_tests97901 +Node: libannocheck_enable_all_tests99067 +Node: libannocheck_disable_all_tests99546 +Node: libannocheck_enable_test100102 +Node: libannocheck_disable_test100770 +Node: libannocheck_enable_profile101439 +Node: libannocheck_get_known_profiles101961 +Node: libannocheck_run_tests102664 +Node: Configure Options103509 +Node: Legacy Scripts105851 +Node: Who Built Me106626 +Node: ABI Checking109386 +Node: Hardening Checks111502 +Node: Checking Archives115588 +Node: GNU FDL118009  End Tag Table diff --git a/doc/annobin.texi b/doc/annobin.texi index e82336d..8136d05 100644 --- a/doc/annobin.texi +++ b/doc/annobin.texi @@ -1836,14 +1836,24 @@ option and re-enabled via the @option{--test-run-path} option. Example: FAIL: rwx-seg test because segment has Read, Write and eXecute flags set @end smallexample -This test checks that the file does not have any segments that have -all three of the @var{read}, @var{write} and @var{execute} -permissions. Code segments should have read and execute permissions, -but they should not be writable as otherwise an attacker can -overwrite the code. Data segments should have read permission, and -possibly write permission as well, but never execute permission -as otherwise an attacker might be able to create their own code in a -data area. +This test checks that the file does not have any segments that are +@enumerate +@item +have all three of the @var{read}, @var{write} and @var{execute} +permissions. +@item +have a non-zero size +@item +are resident in memory when the program runs +@item +do not have an architecture/OS specific type +@end enumerate + +Code segments should have read and execute permissions, but they +should not be writable as otherwise an attacker can overwrite the +code. Data segments should have read permission, and possibly write +permission as well, but never execute permission as otherwise an +attacker might be able to create their own code in a data area. The linker will normally never create a binary file with a segment with all three permissions, but it is possible to force it to do so by -- 2.43.5