@@ -33,6 +33,8 @@ enum kmod_elf_section {
3333 KMOD_ELF_SECTION_STRTAB ,
3434 KMOD_ELF_SECTION_SYMTAB ,
3535 KMOD_ELF_SECTION_VERSIONS ,
36+ KMOD_ELF_SECTION_VERSION_EXT_NAMES ,
37+ KMOD_ELF_SECTION_VERSION_EXT_CRCS ,
3638 KMOD_ELF_SECTION_MAX ,
3739};
3840
@@ -42,6 +44,8 @@ static const char *const section_name_map[] = {
4244 [KMOD_ELF_SECTION_STRTAB ] = ".strtab" ,
4345 [KMOD_ELF_SECTION_SYMTAB ] = ".symtab" ,
4446 [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" ,
4549};
4650
4751struct kmod_elf {
@@ -538,17 +542,15 @@ static inline void elf_get_modversion_lengths(const struct kmod_elf *elf, size_t
538542 }
539543}
540544
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 )
543547{
544548 size_t i , count , crclen , namlen , verlen ;
545549 uint64_t off , sec_off , size ;
546550 struct kmod_modversion * a ;
547551
548552 elf_get_modversion_lengths (elf , & verlen , & crclen , & namlen );
549553
550- * array = NULL ;
551-
552554 sec_off = elf -> sections [KMOD_ELF_SECTION_VERSIONS ].offset ;
553555 size = elf -> sections [KMOD_ELF_SECTION_VERSIONS ].size ;
554556 if (sec_off == 0 )
@@ -591,6 +593,86 @@ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion
591593 return count ;
592594}
593595
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+
594676static int elf_strip_versions_section (const struct kmod_elf * elf , uint8_t * changed )
595677{
596678 uint64_t off , size ;
0 commit comments