Centralize .modinfo detection and property validation.
Unified · Split
| @@ -195,6 +195,38 @@ static unsigned int find_sec(const struct load_info *info, const char *name) · 194 unmodified lines | ||
| 195 | 195 | return 0; |
| 196 | 196 | } |
| 197 | 197 | |
| 198 | +/** | |
| 199 | + * find_any_unique_sec() - Find a unique section index by name | |
| 200 | + * @info: Load info for the module to scan | |
| 201 | + * @name: Name of the section we're looking for | |
| 202 | + * | |
| 203 | + * Locates a unique section by name. Ignores SHF_ALLOC. | |
| 204 | + * | |
| 205 | + * Return: Section index if found uniquely, zero if absent, negative count | |
| 206 | + * of total instances if multiple were found. | |
| 207 | + */ | |
| 208 | +static int find_any_unique_sec(const struct load_info *info, const char *name) | |
| 209 | +{ | |
| 210 | + unsigned int idx; | |
| 211 | + unsigned int count = 0; | |
| 212 | + int i; | |
| 213 | + | |
| 214 | + for (i = 1; i < info->hdr->e_shnum; i++) { | |
| 215 | + if (strcmp(info->secstrings + info->sechdrs[i].sh_name, | |
| 216 | + name) == 0) { | |
| 217 | + count++; | |
| 218 | + idx = i; | |
| 219 | + } | |
| 220 | + } | |
| 221 | + if (count == 1) { | |
| 222 | + return idx; | |
| 223 | + } else if (count == 0) { | |
| 224 | + return 0; | |
| 225 | + } else { | |
| 226 | + return -count; | |
| 227 | + } | |
| 228 | +} | |
| 229 | + | |
| 198 | 230 | /* Find a module section, or NULL. */ |
| 199 | 231 | static void *section_addr(const struct load_info *info, const char *name) |
| 200 | 232 | { |
| @@ -1854,6 +1886,39 @@ static int elf_validity_cache_secstrings(struct load_info *info) · 1653 unmodified lines | ||
| 1854 | 1886 | return 0; |
| 1855 | 1887 | } |
| 1856 | 1888 | |
| 1889 | +/** | |
| 1890 | + * elf_validity_cache_index_info() - Validate and cache modinfo section | |
| 1891 | + * @info: Load info to populate the modinfo index on. | |
| 1892 | + * Must have &load_info->sechdrs and &load_info->secstrings populated | |
| 1893 | + * | |
| 1894 | + * Checks that if there is a .modinfo section, it is unique. | |
| 1895 | + * Then, it caches its index in &load_info->index.info. | |
| 1896 | + * Finally, it tries to populate the name to improve error messages. | |
| 1897 | + * | |
| 1898 | + * Return: %0 if valid, %-ENOEXEC if multiple modinfo sections were found. | |
| 1899 | + */ | |
| 1900 | +static int elf_validity_cache_index_info(struct load_info *info) | |
| 1901 | +{ | |
| 1902 | + int info_idx; | |
| 1903 | + | |
| 1904 | + info_idx = find_any_unique_sec(info, ".modinfo"); | |
| 1905 | + | |
| 1906 | + if (info_idx == 0) | |
| 1907 | + /* Early return, no .modinfo */ | |
| 1908 | + return 0; | |
| 1909 | + | |
| 1910 | + if (info_idx < 0) { | |
| 1911 | + pr_err("Only one .modinfo section must exist.\n"); | |
| 1912 | + return -ENOEXEC; | |
| 1913 | + } | |
| 1914 | + | |
| 1915 | + info->index.info = info_idx; | |
| 1916 | + /* Try to find a name early so we can log errors with a module name */ | |
| 1917 | + info->name = get_modinfo(info, "name"); | |
| 1918 | + | |
| 1919 | + return 0; | |
| 1920 | +} | |
| 1921 | + | |
| 1857 | 1922 | /* |
| 1858 | 1923 | * Check userspace passed ELF module against our expectations, and cache |
| 1859 | 1924 | * useful variables for further processing as we go. |
| @@ -1880,13 +1945,15 @@ static int elf_validity_cache_copy(struct load_info *info, int flags) · 20 unmodified lines | ||
| 1880 | 1945 | Elf_Shdr *shdr; |
| 1881 | 1946 | int err; |
| 1882 | 1947 | unsigned int num_mod_secs = 0, mod_idx; |
| 1883 | − unsigned int num_info_secs = 0, info_idx; | |
| 1884 | 1948 | unsigned int num_sym_secs = 0, sym_idx; |
| 1885 | 1949 | |
| 1886 | 1950 | err = elf_validity_cache_sechdrs(info); |
| 1887 | 1951 | if (err < 0) |
| 1888 | 1952 | return err; |
| 1889 | 1953 | err = elf_validity_cache_secstrings(info); |
| 1954 | + if (err < 0) | |
| 1955 | + return err; | |
| 1956 | + err = elf_validity_cache_index_info(info); | |
| 1890 | 1957 | if (err < 0) |
| 1891 | 1958 | return err; |
| 1892 | 1959 | |
| @@ -1912,24 +1979,11 @@ static int elf_validity_cache_copy(struct load_info *info, int flags) · 19 unmodified lines | ||
| 1912 | 1979 | ".gnu.linkonce.this_module") == 0) { |
| 1913 | 1980 | num_mod_secs++; |
| 1914 | 1981 | mod_idx = i; |
| 1915 | − } else if (strcmp(info->secstrings + shdr->sh_name, | |
| 1916 | − ".modinfo") == 0) { | |
| 1917 | − num_info_secs++; | |
| 1918 | − info_idx = i; | |
| 1919 | 1982 | } |
| 1920 | 1983 | break; |
| 1921 | 1984 | } |
| 1922 | 1985 | } |
| 1923 | 1986 | |
| 1924 | − if (num_info_secs > 1) { | |
| 1925 | − pr_err("Only one .modinfo section must exist.\n"); | |
| 1926 | − goto no_exec; | |
| 1927 | − } else if (num_info_secs == 1) { | |
| 1928 | − /* Try to find a name early so we can log errors with a module name */ | |
| 1929 | − info->index.info = info_idx; | |
| 1930 | − info->name = get_modinfo(info, "name"); | |
| 1931 | − } | |
| 1932 | − | |
| 1933 | 1987 | if (num_sym_secs != 1) { |
| 1934 | 1988 | pr_warn("%s: module has no symbols (stripped?)\n", |
| 1935 | 1989 | info->name ?: "(missing .modinfo section or name field)"); |