1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Module version support 4 * 5 * Copyright (C) 2008 Rusty Russell 6 */ 7 8 #include <linux/module.h> 9 #include <linux/string.h> 10 #include <linux/printk.h> 11 #include "internal.h" 12 13 int check_version(const struct load_info *info, 14 const char *symname, 15 struct module *mod, 16 const u32 *crc) 17 { 18 Elf_Shdr *sechdrs = info->sechdrs; 19 unsigned int versindex = info->index.vers; 20 unsigned int i, num_versions; 21 struct modversion_info *versions; 22 struct modversion_info_ext version_ext; 23 24 /* Exporting module didn't supply crcs? OK, we're already tainted. */ 25 if (!crc) 26 return 1; 27 28 /* If we have extended version info, rely on it */ 29 if (info->index.vers_ext_crc) { 30 for_each_modversion_info_ext(version_ext, info) { 31 if (strcmp(version_ext.name, symname) != 0) 32 continue; 33 if (*version_ext.crc == *crc) 34 return 1; 35 pr_debug("Found checksum %X vs module %X\n", 36 *crc, *version_ext.crc); 37 goto bad_version; 38 } 39 pr_warn_once("%s: no extended symbol version for %s\n", 40 info->name, symname); 41 return 1; 42 } 43 44 /* No versions at all? modprobe --force does this. */ 45 if (versindex == 0) 46 return try_to_force_load(mod, symname) == 0; 47 48 versions = (void *)sechdrs[versindex].sh_addr; 49 num_versions = sechdrs[versindex].sh_size 50 / sizeof(struct modversion_info); 51 52 for (i = 0; i < num_versions; i++) { 53 u32 crcval; 54 55 if (strcmp(versions[i].name, symname) != 0) 56 continue; 57 58 crcval = *crc; 59 if (versions[i].crc == crcval) 60 return 1; 61 pr_debug("Found checksum %X vs module %lX\n", 62 crcval, versions[i].crc); 63 goto bad_version; 64 } 65 66 /* Broken toolchain. Warn once, then let it go.. */ 67 pr_warn_once("%s: no symbol version for %s\n", info->name, symname); 68 return 1; 69 70 bad_version: 71 pr_warn("%s: disagrees about version of symbol %s\n", info->name, symname); 72 return 0; 73 } 74 75 int check_modstruct_version(const struct load_info *info, 76 struct module *mod) 77 { 78 struct find_symbol_arg fsa = { 79 .name = "module_layout", 80 .gplok = true, 81 }; 82 bool have_symbol; 83 84 /* 85 * Since this should be found in kernel (which can't be removed), no 86 * locking is necessary. Regardless use a RCU read section to keep 87 * lockdep happy. 88 */ 89 scoped_guard(rcu) 90 have_symbol = find_symbol(&fsa); 91 BUG_ON(!have_symbol); 92 93 return check_version(info, "module_layout", mod, fsa.crc); 94 } 95 96 /* First part is kernel version, which we ignore if module has crcs. */ 97 int same_magic(const char *amagic, const char *bmagic, 98 bool has_crcs) 99 { 100 if (has_crcs) { 101 amagic += strcspn(amagic, " "); 102 bmagic += strcspn(bmagic, " "); 103 } 104 return strcmp(amagic, bmagic) == 0; 105 } 106 107 void modversion_ext_start(const struct load_info *info, 108 struct modversion_info_ext *start) 109 { 110 unsigned int crc_idx = info->index.vers_ext_crc; 111 unsigned int name_idx = info->index.vers_ext_name; 112 Elf_Shdr *sechdrs = info->sechdrs; 113 114 /* 115 * Both of these fields are needed for this to be useful 116 * Any future fields should be initialized to NULL if absent. 117 */ 118 if (crc_idx == 0 || name_idx == 0) { 119 start->remaining = 0; 120 return; 121 } 122 123 start->crc = (const u32 *)sechdrs[crc_idx].sh_addr; 124 start->name = (const char *)sechdrs[name_idx].sh_addr; 125 start->remaining = sechdrs[crc_idx].sh_size / sizeof(*start->crc); 126 } 127 128 void modversion_ext_advance(struct modversion_info_ext *vers) 129 { 130 vers->remaining--; 131 vers->crc++; 132 vers->name += strlen(vers->name) + 1; 133 } 134 135 /* 136 * Generate the signature for all relevant module structures here. 137 * If these change, we don't want to try to parse the module. 138 */ 139 void module_layout(struct module *mod, 140 struct modversion_info *ver, 141 struct kernel_param *kp, 142 struct kernel_symbol *ks, 143 struct tracepoint * const *tp) 144 { 145 } 146 EXPORT_SYMBOL(module_layout); 147