99 normalize_path:: NormalizePath ,
1010 object:: {
1111 elf:: {
12- FileHeader32 , FileHeader64 , ET_DYN , ET_EXEC , STB_GLOBAL , STB_WEAK , STV_DEFAULT ,
12+ FileHeader32 , FileHeader64 , ET_DYN , ET_EXEC , SHN_UNDEF , STB_GLOBAL , STB_WEAK , STV_DEFAULT ,
1313 STV_HIDDEN ,
1414 } ,
1515 macho:: { MachHeader32 , MachHeader64 , MH_OBJECT , MH_TWOLEVEL } ,
@@ -265,6 +265,25 @@ static ELF_ALLOWED_LIBRARIES_BY_TRIPLE: Lazy<HashMap<&'static str, Vec<&'static
265265 . collect ( )
266266 } ) ;
267267
268+ static ELF_ALLOWED_LIBRARIES_BY_MODULE : Lazy < HashMap < & ' static str , Vec < & ' static str > > > =
269+ Lazy :: new ( || {
270+ [
271+ (
272+ // libcrypt is provided by the system, but only on older distros.
273+ "_crypt" ,
274+ vec ! [ "libcrypt.so.1" ] ,
275+ ) ,
276+ (
277+ // libtcl and libtk are shipped in our distribution.
278+ "_tkinter" ,
279+ vec ! [ "libtcl8.6.so" , "libtk8.6.so" ] ,
280+ ) ,
281+ ]
282+ . iter ( )
283+ . cloned ( )
284+ . collect ( )
285+ } ) ;
286+
268287static DARWIN_ALLOWED_DYLIBS : Lazy < Vec < MachOAllowedDylib > > = Lazy :: new ( || {
269288 [
270289 MachOAllowedDylib {
@@ -501,6 +520,29 @@ static IOS_ALLOWED_DYLIBS: Lazy<Vec<MachOAllowedDylib>> = Lazy::new(|| {
501520 . to_vec ( )
502521} ) ;
503522
523+ static ALLOWED_DYLIBS_BY_MODULE : Lazy < HashMap < & ' static str , Vec < MachOAllowedDylib > > > =
524+ Lazy :: new ( || {
525+ [ (
526+ // libtcl and libtk are shipped in our distribution.
527+ "_tkinter" ,
528+ vec ! [
529+ MachOAllowedDylib {
530+ name: "@rpath/libtcl8.6.dylib" . to_string( ) ,
531+ max_compatibility_version: "8.6.0" . try_into( ) . unwrap( ) ,
532+ required: true ,
533+ } ,
534+ MachOAllowedDylib {
535+ name: "@rpath/libtk8.6.dylib" . to_string( ) ,
536+ max_compatibility_version: "8.6.0" . try_into( ) . unwrap( ) ,
537+ required: true ,
538+ } ,
539+ ] ,
540+ ) ]
541+ . iter ( )
542+ . cloned ( )
543+ . collect ( )
544+ } ) ;
545+
504546static PLATFORM_TAG_BY_TRIPLE : Lazy < HashMap < & ' static str , & ' static str > > = Lazy :: new ( || {
505547 [
506548 ( "aarch64-apple-darwin" , "macosx-11.0-arm64" ) ,
@@ -544,9 +586,12 @@ const ELF_BANNED_SYMBOLS: &[&str] = &[
544586/// We use this list to spot test behavior of symbols belonging to dependency packages.
545587/// The list is obviously not complete.
546588const DEPENDENCY_PACKAGE_SYMBOLS : & [ & str ] = & [
547- // libX11
548- "XClearWindow" ,
549- "XFlush" ,
589+ /* TODO(geofft): Tk provides these as no-op stubs on macOS, make it
590+ * stop doing that so we can reenable the check
591+ * // libX11
592+ * "XClearWindow",
593+ * "XFlush",
594+ */
550595 // OpenSSL
551596 "BIO_ADDR_new" ,
552597 "BN_new" ,
@@ -591,6 +636,11 @@ const DEPENDENCY_PACKAGE_SYMBOLS: &[&str] = &[
591636 // liblzma
592637 "lzma_index_init" ,
593638 "lzma_stream_encoder" ,
639+ ] ;
640+
641+ // TODO(geofft): Conditionally prohibit these exported symbols
642+ // everywhere except libtcl and libtk. This should be a hashmap
643+ const _DEPENDENCY_PACKAGE_SYMBOLS_BUNDLED: & [ & str ] = & [
594644 // tcl
595645 "Tcl_Alloc" ,
596646 "Tcl_ChannelName" ,
@@ -967,11 +1017,13 @@ fn validate_elf<Elf: FileHeader<Endian = Endianness>>(
9671017 allowed_libraries. push ( "libc.so" . to_string ( ) ) ;
9681018 }
9691019
970- // Allow the _crypt extension module - and only it - to link against libcrypt,
971- // which is no longer universally present in Linux distros .
1020+ // Allow certain extension modules to link against shared libraries
1021+ // (either from the system or from our distribution) .
9721022 if let Some ( filename) = path. file_name ( ) {
973- if filename. to_string_lossy ( ) . starts_with ( "_crypt" ) {
974- allowed_libraries. push ( "libcrypt.so.1" . to_string ( ) ) ;
1023+ if let Some ( ( module, _) ) = filename. to_string_lossy ( ) . split_once ( ".cpython-" ) {
1024+ if let Some ( extra) = ELF_ALLOWED_LIBRARIES_BY_MODULE . get ( module) {
1025+ allowed_libraries. extend ( extra. iter ( ) . map ( |x| x. to_string ( ) ) ) ;
1026+ }
9751027 }
9761028 }
9771029
@@ -1109,6 +1161,7 @@ fn validate_elf<Elf: FileHeader<Endian = Endianness>>(
11091161 // to prevent them from being exported.
11101162 if DEPENDENCY_PACKAGE_SYMBOLS . contains ( & name. as_ref ( ) )
11111163 && matches ! ( symbol. st_bind( ) , STB_GLOBAL | STB_WEAK )
1164+ && symbol. st_shndx ( endian) != SHN_UNDEF
11121165 && symbol. st_visibility ( ) != STV_HIDDEN
11131166 {
11141167 context. errors . push ( format ! (
@@ -1124,6 +1177,7 @@ fn validate_elf<Elf: FileHeader<Endian = Endianness>>(
11241177 if filename. starts_with ( "libpython" )
11251178 && filename. ends_with ( ".so.1.0" )
11261179 && matches ! ( symbol. st_bind( ) , STB_GLOBAL | STB_WEAK )
1180+ && symbol. st_shndx ( endian) != SHN_UNDEF
11271181 && symbol. st_visibility ( ) == STV_DEFAULT
11281182 {
11291183 context. libpython_exported_symbols . insert ( name. to_string ( ) ) ;
@@ -1225,7 +1279,16 @@ fn validate_macho<Mach: MachHeader<Endian = Endianness>>(
12251279
12261280 dylib_names. push ( lib. clone ( ) ) ;
12271281
1228- let allowed = allowed_dylibs_for_triple ( target_triple) ;
1282+ let mut allowed = allowed_dylibs_for_triple ( target_triple) ;
1283+ // Allow certain extension modules to link against shared libraries
1284+ // (either from the system or from our distribution).
1285+ if let Some ( filename) = path. file_name ( ) {
1286+ if let Some ( ( module, _) ) = filename. to_string_lossy ( ) . split_once ( ".cpython-" ) {
1287+ if let Some ( extra) = ALLOWED_DYLIBS_BY_MODULE . get ( module) {
1288+ allowed. extend ( extra. clone ( ) ) ;
1289+ }
1290+ }
1291+ }
12291292
12301293 if let Some ( entry) = allowed. iter ( ) . find ( |l| l. name == lib) {
12311294 let load_version =
0 commit comments