@@ -33,6 +33,8 @@ enum kmod_elf_section {
33
33
KMOD_ELF_SECTION_STRTAB ,
34
34
KMOD_ELF_SECTION_SYMTAB ,
35
35
KMOD_ELF_SECTION_VERSIONS ,
36
+ KMOD_ELF_SECTION_VERSION_EXT_NAMES ,
37
+ KMOD_ELF_SECTION_VERSION_EXT_CRCS ,
36
38
KMOD_ELF_SECTION_MAX ,
37
39
};
38
40
@@ -42,6 +44,8 @@ static const char *const section_name_map[] = {
42
44
[KMOD_ELF_SECTION_STRTAB ] = ".strtab" ,
43
45
[KMOD_ELF_SECTION_SYMTAB ] = ".symtab" ,
44
46
[KMOD_ELF_SECTION_VERSIONS ] = "__versions" ,
47
+ [KMOD_ELF_SECTION_VERSION_EXT_NAMES ] = "__version_ext_names" ,
48
+ [KMOD_ELF_SECTION_VERSION_EXT_CRCS ] = "__version_ext_crcs" ,
45
49
};
46
50
47
51
struct kmod_elf {
@@ -538,17 +542,15 @@ static inline void elf_get_modversion_lengths(const struct kmod_elf *elf, size_t
538
542
}
539
543
}
540
544
541
- /* array will be allocated with strings in a single malloc, just free *array */
542
- int kmod_elf_get_modversions ( const struct kmod_elf * elf , struct kmod_modversion * * array )
545
+ static int kmod_elf_get_basic_modversions ( const struct kmod_elf * elf ,
546
+ struct kmod_modversion * * array )
543
547
{
544
548
size_t i , count , crclen , namlen , verlen ;
545
549
uint64_t off , sec_off , size ;
546
550
struct kmod_modversion * a ;
547
551
548
552
elf_get_modversion_lengths (elf , & verlen , & crclen , & namlen );
549
553
550
- * array = NULL ;
551
-
552
554
sec_off = elf -> sections [KMOD_ELF_SECTION_VERSIONS ].offset ;
553
555
size = elf -> sections [KMOD_ELF_SECTION_VERSIONS ].size ;
554
556
if (sec_off == 0 )
@@ -591,6 +593,86 @@ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion
591
593
return count ;
592
594
}
593
595
596
+ static int kmod_elf_get_extended_modversions (const struct kmod_elf * elf ,
597
+ struct kmod_modversion * * array )
598
+ {
599
+ uint64_t name_off , name_size , crc_off , crc_size ;
600
+ const char * name_cursor ;
601
+ int count , i , ret ;
602
+
603
+ name_off = elf -> sections [KMOD_ELF_SECTION_VERSION_EXT_NAMES ].offset ;
604
+ name_size = elf -> sections [KMOD_ELF_SECTION_VERSION_EXT_NAMES ].size ;
605
+ crc_off = elf -> sections [KMOD_ELF_SECTION_VERSION_EXT_CRCS ].offset ;
606
+ crc_size = elf -> sections [KMOD_ELF_SECTION_VERSION_EXT_CRCS ].size ;
607
+
608
+ if ((name_off == 0 ) || (crc_off == 0 ))
609
+ return - ENODATA ;
610
+
611
+ if (crc_size == 0 )
612
+ return 0 ;
613
+
614
+ if (crc_size % sizeof (uint32_t ) != 0 )
615
+ return - EINVAL ;
616
+
617
+ count = crc_size / sizeof (uint32_t );
618
+ * array = malloc (sizeof (struct kmod_modversion ) * count );
619
+ if (* array == NULL )
620
+ return - errno ;
621
+
622
+ for (name_cursor = elf_get_mem (elf , name_off ), i = 0 ; i < count ; i ++ ) {
623
+ size_t len ;
624
+ uint32_t crc ;
625
+
626
+ if (name_size == 0 ) {
627
+ ELFDBG (elf , "fewer symbol names than crcs\n" );
628
+ ret = - EINVAL ;
629
+ goto release_array ;
630
+ }
631
+ len = strnlen (name_cursor , name_size );
632
+ if (len == name_size ) {
633
+ ELFDBG (elf , "last symbol name not null-terminated\n" );
634
+ ret = - EINVAL ;
635
+ goto release_array ;
636
+ }
637
+ crc = elf_get_uint (elf , crc_off , sizeof (uint32_t ));
638
+
639
+ /* PPC sometimes prefixes names with `.` */
640
+ if (name_cursor [0 ] == '.' ) {
641
+ name_cursor ++ ;
642
+ len -- ;
643
+ }
644
+
645
+ (* array )[i ].crc = crc ;
646
+ (* array )[i ].bind = KMOD_SYMBOL_UNDEF ;
647
+ (* array )[i ].symbol = name_cursor ;
648
+
649
+ /* len doesn't include the NUL, but our pointers and size do */
650
+ name_cursor += len + 1 ;
651
+ name_size -= len + 1 ;
652
+ crc_off += sizeof (uint32_t );
653
+ }
654
+
655
+ return count ;
656
+
657
+ release_array :
658
+ free (* array );
659
+ return ret ;
660
+ }
661
+
662
+ /* array will be allocated with strings in a single malloc, just free *array */
663
+ int kmod_elf_get_modversions (const struct kmod_elf * elf , struct kmod_modversion * * array )
664
+ {
665
+ int ret ;
666
+
667
+ * array = NULL ;
668
+
669
+ ret = kmod_elf_get_extended_modversions (elf , array );
670
+ /* if no extended modversions, fall back, otherwise propagate error */
671
+ if (ret != - ENODATA )
672
+ return ret ;
673
+ return kmod_elf_get_basic_modversions (elf , array );
674
+ }
675
+
594
676
static int elf_strip_versions_section (const struct kmod_elf * elf , uint8_t * changed )
595
677
{
596
678
uint64_t off , size ;
0 commit comments