@@ -401,12 +401,29 @@ fn allowed_dylibs_for_triple(triple: &str) -> Vec<MachOAllowedDylib> {
401
401
}
402
402
403
403
fn validate_elf (
404
+ json : & PythonJsonMain ,
404
405
target_triple : & str ,
405
406
python_major_minor : & str ,
406
407
path : & Path ,
407
408
elf : & goblin:: elf:: Elf ,
408
409
bytes : & [ u8 ] ,
409
410
) -> Result < Vec < String > > {
411
+ let mut system_links = BTreeSet :: new ( ) ;
412
+ for link in & json. build_info . core . links {
413
+ if link. system . unwrap_or_default ( ) {
414
+ system_links. insert ( link. name . as_str ( ) ) ;
415
+ }
416
+ }
417
+ for extension in json. build_info . extensions . values ( ) {
418
+ for variant in extension {
419
+ for link in & variant. links {
420
+ if link. system . unwrap_or_default ( ) {
421
+ system_links. insert ( link. name . as_str ( ) ) ;
422
+ }
423
+ }
424
+ }
425
+ }
426
+
410
427
let mut errors = vec ! [ ] ;
411
428
412
429
let wanted_cpu_type = match target_triple {
@@ -453,6 +470,48 @@ fn validate_elf(
453
470
if !allowed_libraries. contains ( & lib. to_string ( ) ) {
454
471
errors. push ( format ! ( "{} loads illegal library {}" , path. display( ) , lib) ) ;
455
472
}
473
+
474
+ // Most linked libraries should have an annotation in the JSON metadata.
475
+ let requires_annotation = !lib. contains ( "libpython" )
476
+ && !lib. starts_with ( "ld-linux" )
477
+ && !lib. starts_with ( "ld64.so" )
478
+ && !lib. starts_with ( "ld.so" )
479
+ && !lib. starts_with ( "libc.so" )
480
+ && !lib. starts_with ( "libgcc_s.so" ) ;
481
+
482
+ if requires_annotation {
483
+ if lib. starts_with ( "lib" ) {
484
+ if let Some ( index) = lib. rfind ( ".so" ) {
485
+ let lib_name = & lib[ 3 ..index] ;
486
+
487
+ // There should be a system links entry for this library in the JSON
488
+ // metadata.
489
+ //
490
+ // Nominally we would look at where this ELF came from and make sure
491
+ // the annotation is present in its section (e.g. core or extension).
492
+ // But this is more work.
493
+ if !system_links. contains ( lib_name) {
494
+ errors. push ( format ! (
495
+ "{} library load of {} does not have system link build annotation" ,
496
+ path. display( ) ,
497
+ lib
498
+ ) ) ;
499
+ }
500
+ } else {
501
+ errors. push ( format ! (
502
+ "{} library load of {} does not have .so extension" ,
503
+ path. display( ) ,
504
+ lib
505
+ ) ) ;
506
+ }
507
+ } else {
508
+ errors. push ( format ! (
509
+ "{} library load of {} does not begin with lib" ,
510
+ path. display( ) ,
511
+ lib
512
+ ) ) ;
513
+ }
514
+ }
456
515
}
457
516
458
517
let wanted_glibc_max_version = GLIBC_MAX_VERSION_BY_TRIPLE
@@ -581,6 +640,7 @@ fn validate_pe(path: &Path, pe: &goblin::pe::PE) -> Result<Vec<String>> {
581
640
582
641
/// Attempt to parse data as an object file and validate it.
583
642
fn validate_possible_object_file (
643
+ json : & PythonJsonMain ,
584
644
python_major_minor : & str ,
585
645
triple : & str ,
586
646
path : & Path ,
@@ -593,6 +653,7 @@ fn validate_possible_object_file(
593
653
match object {
594
654
goblin:: Object :: Elf ( elf) => {
595
655
errors. extend ( validate_elf (
656
+ json,
596
657
triple,
597
658
python_major_minor,
598
659
path. as_ref ( ) ,
@@ -727,17 +788,24 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
727
788
let mut entries = tf. entries ( ) ?;
728
789
729
790
let mut wanted_python_paths = BTreeSet :: new ( ) ;
791
+ let mut json = None ;
730
792
731
793
let mut entry = entries. next ( ) . unwrap ( ) ?;
732
794
if entry. path ( ) ?. display ( ) . to_string ( ) == "python/PYTHON.json" {
733
795
seen_paths. insert ( entry. path ( ) ?. to_path_buf ( ) ) ;
734
796
735
797
let mut data = Vec :: new ( ) ;
736
798
entry. read_to_end ( & mut data) ?;
737
- let json = parse_python_json ( & data) . context ( "parsing PYTHON.json" ) ?;
738
- errors. extend ( validate_json ( & json, triple, is_debug) ?) ;
739
-
740
- wanted_python_paths. extend ( json. python_paths . values ( ) . map ( |x| format ! ( "python/{}" , x) ) ) ;
799
+ json = Some ( parse_python_json ( & data) . context ( "parsing PYTHON.json" ) ?) ;
800
+ errors. extend ( validate_json ( json. as_ref ( ) . unwrap ( ) , triple, is_debug) ?) ;
801
+
802
+ wanted_python_paths. extend (
803
+ json. as_ref ( )
804
+ . unwrap ( )
805
+ . python_paths
806
+ . values ( )
807
+ . map ( |x| format ! ( "python/{}" , x) ) ,
808
+ ) ;
741
809
} else {
742
810
errors. push ( format ! (
743
811
"1st archive entry should be for python/PYTHON.json; got {}" ,
@@ -770,8 +838,13 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
770
838
let mut data = Vec :: new ( ) ;
771
839
entry. read_to_end ( & mut data) ?;
772
840
773
- let ( local_errors, local_seen_dylibs) =
774
- validate_possible_object_file ( python_major_minor, & triple, & path, & data) ?;
841
+ let ( local_errors, local_seen_dylibs) = validate_possible_object_file (
842
+ json. as_ref ( ) . unwrap ( ) ,
843
+ python_major_minor,
844
+ & triple,
845
+ & path,
846
+ & data,
847
+ ) ?;
775
848
errors. extend ( local_errors) ;
776
849
seen_dylibs. extend ( local_seen_dylibs) ;
777
850
@@ -790,6 +863,7 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
790
863
) ) ;
791
864
792
865
let ( local_errors, local_seen_dylibs) = validate_possible_object_file (
866
+ json. as_ref ( ) . unwrap ( ) ,
793
867
python_major_minor,
794
868
& triple,
795
869
& member_path,
@@ -801,8 +875,7 @@ fn validate_distribution(dist_path: &Path) -> Result<Vec<String>> {
801
875
}
802
876
803
877
if path == PathBuf :: from ( "python/PYTHON.json" ) {
804
- let json = parse_python_json ( & data) . context ( "parsing PYTHON.json" ) ?;
805
- errors. extend ( validate_json ( & json, triple, is_debug) ?) ;
878
+ errors. push ( "python/PYTHON.json seen twice" . to_string ( ) ) ;
806
879
}
807
880
}
808
881
0 commit comments