@@ -643,6 +643,110 @@ def test_current_umbrella_has_no_backend_types(self):
643643 self .assertEqual ([], audit .header_violations (result , []))
644644
645645
646+ # Exact /usr/bin/readelf -d stdout from FreeBSD package job 120773457461,
647+ # run 40060736308, artifact 12550179871; SHA256 1f60a5922ad44f8a14c69bed7b378558f0f3c02056597781045b37e9610a4a45.
648+ FREEBSD_NATIVE_DYNAMIC = (
649+ '\n '
650+ 'Dynamic section at offset 0x27530 contains 30 entries:\n '
651+ ' Tag Type Name/Value\n '
652+ ' 0x000000000000001d RUNPATH Library runpath: [/tmp/v3-package-40060736308-1/package-evidence/matrix/tls-no/prefix/lib:/tmp/v3-package-40060736308-1/package-evidence/prerequisites/provider/lib:/tmp/v3-package-40060736308-1/package-evidence/toolchain/lib]\n '
653+ ' 0x0000000000000001 NEEDED Shared library: [libhttpserver.so.3]\n '
654+ ' 0x0000000000000001 NEEDED Shared library: [libc++.so.1]\n '
655+ ' 0x0000000000000001 NEEDED Shared library: [libcxxrt.so.1]\n '
656+ ' 0x0000000000000001 NEEDED Shared library: [libm.so.5]\n '
657+ ' 0x0000000000000001 NEEDED Shared library: [libgcc_s.so.1]\n '
658+ ' 0x0000000000000001 NEEDED Shared library: [libthr.so.3]\n '
659+ ' 0x0000000000000001 NEEDED Shared library: [libc.so.7]\n '
660+ ' 0x0000000000000015 DEBUG 0x0\n '
661+ ' 0x0000000000000007 RELA 0x205d40\n '
662+ ' 0x0000000000000008 RELASZ 432 (bytes)\n '
663+ ' 0x0000000000000009 RELAENT 24 (bytes)\n '
664+ ' 0x0000000000000017 JMPREL 0x205ef0\n '
665+ ' 0x0000000000000002 PLTRELSZ 2040 (bytes)\n '
666+ ' 0x0000000000000003 PLTGOT 0x22a970\n '
667+ ' 0x0000000000000014 PLTREL RELA\n '
668+ ' 0x0000000000000006 SYMTAB 0x200308\n '
669+ ' 0x000000000000000b SYMENT 24 (bytes)\n '
670+ ' 0x0000000000000005 STRTAB 0x2021b8\n '
671+ ' 0x000000000000000a STRSZ 15233 (bytes)\n '
672+ ' 0x000000006ffffef5 GNU_HASH 0x201808\n '
673+ ' 0x0000000000000004 HASH 0x201b70\n '
674+ ' 0x0000000000000019 INIT_ARRAY \n '
675+ ' 0x000000000000001b INIT_ARRAYSZ 8 (bytes)\n '
676+ ' 0x000000000000000c INIT 0x227f80\n '
677+ ' 0x000000000000000d FINI 0x227f8c\n '
678+ ' 0x000000006ffffff0 VERSYM 0x2015c8\n '
679+ ' 0x000000006ffffffe VERNEED 0x201758\n '
680+ ' 0x000000006fffffff VERNEEDNUM 4\n '
681+ ' 0x0000000000000000 NULL 0x0\n '
682+ )
683+
684+
685+ class ElfInspectorTest (unittest .TestCase ):
686+ def inspect (self , dynamic , resolved = '' , host = 'FreeBSD' ):
687+ def command (argv , ** kwargs ):
688+ output = {'readelf' : dynamic , 'ldd' : resolved }[argv [0 ]]
689+ return subprocess .CompletedProcess (argv , 0 , output , '' )
690+ audit .COMMANDS .clear ()
691+ with patch .object (audit .platform , 'system' , return_value = host ), \
692+ patch .object (subprocess , 'run' , side_effect = command ):
693+ return audit .platform_inspector ('/package/consumer' )
694+
695+ def test_captured_freebsd_needed_rows_resolve_all_seven_dependencies (self ):
696+ names = ['libhttpserver.so.3' , 'libc++.so.1' , 'libcxxrt.so.1' , 'libm.so.5' ,
697+ 'libgcc_s.so.1' , 'libthr.so.3' , 'libc.so.7' ]
698+ resolved = '' .join (f' { name } => /selected/lib/{ name } (0x1)\n ' for name in names )
699+
700+ dependencies = self .inspect (FREEBSD_NATIVE_DYNAMIC , resolved )
701+
702+ self .assertEqual ([(name , '/selected/lib/' + name ) for name in names ], dependencies )
703+ self .assertEqual (FREEBSD_NATIVE_DYNAMIC , audit .COMMANDS [0 ]['stdout' ])
704+ self .assertEqual (0 , audit .COMMANDS [0 ]['returncode' ])
705+ self .assertEqual ('' , audit .COMMANDS [0 ]['stderr' ])
706+
707+ def test_elf_inspection_requires_dynamic_section_and_nonempty_dependencies (self ):
708+ for host in ('FreeBSD' , 'Linux' ):
709+ for dynamic , error in (
710+ ('0x1 NEEDED Shared library: [libc.so.7]\n ' , 'missing ELF dynamic section' ),
711+ ('Dynamic section at offset 0 contains 1 entry:\n 0x0 NULL 0x0\n ' ,
712+ 'empty ELF dependency inspection' )):
713+ with self .subTest (host = host , dynamic = dynamic ), self .assertRaisesRegex (audit .AuditError , error ):
714+ self .inspect (dynamic , host = host )
715+
716+ def test_needed_dependencies_require_successful_ldd_resolution (self ):
717+ for host in ('FreeBSD' , 'Linux' ):
718+ for resolved , error in (
719+ ('libc++.so.1 => not found\n ' , 'unresolved ELF dependency' ),
720+ ('libhttpserver.so.3 => /package/lib/libhttpserver.so.3 (0x1)\n ' ,
721+ r'missing resolution for libc\+\+\.so\.1' )):
722+ with self .subTest (host = host , resolved = resolved ), self .assertRaisesRegex (audit .AuditError , error ):
723+ self .inspect (FREEBSD_NATIVE_DYNAMIC , resolved , host )
724+
725+ def test_malformed_tags_and_non_needed_noise_cannot_supply_dependencies (self ):
726+ for row in (
727+ '0x1 NOTNEEDED Shared library: [libnoise.so]' ,
728+ '0x1 NEEDED_EXTRA Shared library: [libnoise.so]' ,
729+ '0x1 (NEEDED Shared library: [libnoise.so]' ,
730+ '0x1 NEEDED) Shared library: [libnoise.so]' ,
731+ 'diagnostic (NEEDED) Shared library: [libnoise.so]' ,
732+ '0x1 RUNPATH Shared library: [libnoise.so]' ,
733+ '0x1 NEEDED Library runpath: [libnoise.so]' ,
734+ '0x1 NEEDED Shared library: []' ,
735+ '0x1 NEEDED Shared library: [libnoise.so' ,
736+ '0x1 (NEEDED) Shared library: [libnoise.so] trailing noise' ):
737+ with self .subTest (row = row ), self .assertRaisesRegex (audit .AuditError , 'empty ELF dependency inspection' ):
738+ self .inspect ('Dynamic section at offset 0 contains 1 entry:\n ' + row + '\n ' ,
739+ 'libnoise.so => /selected/lib/libnoise.so (0x1)\n ' )
740+
741+ def test_non_needed_rows_do_not_add_edges_to_valid_gnu_inspection (self ):
742+ dynamic = ('Dynamic section at offset 0 contains 3 entries:\n '
743+ ' 0x1 (NEEDED) Shared library: [libc.so.6]\n '
744+ ' 0x1 NOTNEEDED Shared library: [libnoise.so]\n '
745+ ' diagnostic (NEEDED) Shared library: [libnoise.so]\n ' )
746+ dependencies = self .inspect (dynamic , 'libc.so.6 => /lib/libc.so.6 (0x1)\n ' , 'Linux' )
747+ self .assertEqual ([('libc.so.6' , '/lib/libc.so.6' )], dependencies )
748+
749+
646750class AuditFixturePathTest (unittest .TestCase ):
647751 def test_unwind_contract_under_symlinked_temporary_root (self ):
648752 original_tempdir = tempfile .tempdir
0 commit comments