@@ -2073,6 +2073,82 @@ static int elf_validity_cache_index_str(struct load_info *info)
20732073 return 0 ;
20742074}
20752075
2076+ /**
2077+ * elf_validity_cache_index_versions() - Validate and cache version indices
2078+ * @info: Load info to cache version indices in.
2079+ * Must have &load_info->sechdrs and &load_info->secstrings populated.
2080+ * @flags: Load flags, relevant to suppress version loading, see
2081+ * uapi/linux/module.h
2082+ *
2083+ * If we're ignoring modversions based on @flags, zero all version indices
2084+ * and return validity. Othewrise check:
2085+ *
2086+ * * If "__version_ext_crcs" is present, "__version_ext_names" is present
2087+ * * There is a name present for every crc
2088+ *
2089+ * Then populate:
2090+ *
2091+ * * &load_info->index.vers
2092+ * * &load_info->index.vers_ext_crc
2093+ * * &load_info->index.vers_ext_names
2094+ *
2095+ * if present.
2096+ *
2097+ * Return: %0 if valid, %-ENOEXEC on failure.
2098+ */
2099+ static int elf_validity_cache_index_versions (struct load_info * info , int flags )
2100+ {
2101+ unsigned int vers_ext_crc ;
2102+ unsigned int vers_ext_name ;
2103+ size_t crc_count ;
2104+ size_t remaining_len ;
2105+ size_t name_size ;
2106+ char * name ;
2107+
2108+ /* If modversions were suppressed, pretend we didn't find any */
2109+ if (flags & MODULE_INIT_IGNORE_MODVERSIONS ) {
2110+ info -> index .vers = 0 ;
2111+ info -> index .vers_ext_crc = 0 ;
2112+ info -> index .vers_ext_name = 0 ;
2113+ return 0 ;
2114+ }
2115+
2116+ vers_ext_crc = find_sec (info , "__version_ext_crcs" );
2117+ vers_ext_name = find_sec (info , "__version_ext_names" );
2118+
2119+ /* If we have one field, we must have the other */
2120+ if (!!vers_ext_crc != !!vers_ext_name ) {
2121+ pr_err ("extended version crc+name presence does not match" );
2122+ return - ENOEXEC ;
2123+ }
2124+
2125+ /*
2126+ * If we have extended version information, we should have the same
2127+ * number of entries in every section.
2128+ */
2129+ if (vers_ext_crc ) {
2130+ crc_count = info -> sechdrs [vers_ext_crc ].sh_size / sizeof (u32 );
2131+ name = (void * )info -> hdr +
2132+ info -> sechdrs [vers_ext_name ].sh_offset ;
2133+ remaining_len = info -> sechdrs [vers_ext_name ].sh_size ;
2134+
2135+ while (crc_count -- ) {
2136+ name_size = strnlen (name , remaining_len ) + 1 ;
2137+ if (name_size > remaining_len ) {
2138+ pr_err ("more extended version crcs than names" );
2139+ return - ENOEXEC ;
2140+ }
2141+ remaining_len -= name_size ;
2142+ name += name_size ;
2143+ }
2144+ }
2145+
2146+ info -> index .vers = find_sec (info , "__versions" );
2147+ info -> index .vers_ext_crc = vers_ext_crc ;
2148+ info -> index .vers_ext_name = vers_ext_name ;
2149+ return 0 ;
2150+ }
2151+
20762152/**
20772153 * elf_validity_cache_index() - Resolve, validate, cache section indices
20782154 * @info: Load info to read from and update.
@@ -2087,9 +2163,7 @@ static int elf_validity_cache_index_str(struct load_info *info)
20872163 * * elf_validity_cache_index_mod()
20882164 * * elf_validity_cache_index_sym()
20892165 * * elf_validity_cache_index_str()
2090- *
2091- * If versioning is not suppressed via flags, load the version index from
2092- * a section called "__versions" with no validation.
2166+ * * elf_validity_cache_index_versions()
20932167 *
20942168 * If CONFIG_SMP is enabled, load the percpu section by name with no
20952169 * validation.
@@ -2112,11 +2186,9 @@ static int elf_validity_cache_index(struct load_info *info, int flags)
21122186 err = elf_validity_cache_index_str (info );
21132187 if (err < 0 )
21142188 return err ;
2115-
2116- if (flags & MODULE_INIT_IGNORE_MODVERSIONS )
2117- info -> index .vers = 0 ; /* Pretend no __versions section! */
2118- else
2119- info -> index .vers = find_sec (info , "__versions" );
2189+ err = elf_validity_cache_index_versions (info , flags );
2190+ if (err < 0 )
2191+ return err ;
21202192
21212193 info -> index .pcpu = find_pcpusec (info );
21222194
@@ -2327,6 +2399,10 @@ static int rewrite_section_headers(struct load_info *info, int flags)
23272399
23282400 /* Track but don't keep modinfo and version sections. */
23292401 info -> sechdrs [info -> index .vers ].sh_flags &= ~(unsigned long )SHF_ALLOC ;
2402+ info -> sechdrs [info -> index .vers_ext_crc ].sh_flags &=
2403+ ~(unsigned long )SHF_ALLOC ;
2404+ info -> sechdrs [info -> index .vers_ext_name ].sh_flags &=
2405+ ~(unsigned long )SHF_ALLOC ;
23302406 info -> sechdrs [info -> index .info ].sh_flags &= ~(unsigned long )SHF_ALLOC ;
23312407
23322408 return 0 ;
0 commit comments