linux/arch/x86/kernel/module.c
<<
>>
Prefs
   1/*  Kernel module help for x86.
   2    Copyright (C) 2001 Rusty Russell.
   3
   4    This program is free software; you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 2 of the License, or
   7    (at your option) any later version.
   8
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13
  14    You should have received a copy of the GNU General Public License
  15    along with this program; if not, write to the Free Software
  16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17*/
  18
  19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  20
  21#include <linux/moduleloader.h>
  22#include <linux/elf.h>
  23#include <linux/vmalloc.h>
  24#include <linux/fs.h>
  25#include <linux/string.h>
  26#include <linux/kernel.h>
  27#include <linux/kasan.h>
  28#include <linux/bug.h>
  29#include <linux/mm.h>
  30#include <linux/gfp.h>
  31#include <linux/jump_label.h>
  32#include <linux/random.h>
  33
  34#include <asm/page.h>
  35#include <asm/pgtable.h>
  36#include <asm/setup.h>
  37
  38#if 0
  39#define DEBUGP(fmt, ...)                                \
  40        printk(KERN_DEBUG fmt, ##__VA_ARGS__)
  41#else
  42#define DEBUGP(fmt, ...)                                \
  43do {                                                    \
  44        if (0)                                          \
  45                printk(KERN_DEBUG fmt, ##__VA_ARGS__);  \
  46} while (0)
  47#endif
  48
  49#ifdef CONFIG_RANDOMIZE_BASE
  50static unsigned long module_load_offset;
  51
  52/* Mutex protects the module_load_offset. */
  53static DEFINE_MUTEX(module_kaslr_mutex);
  54
  55static unsigned long int get_module_load_offset(void)
  56{
  57        if (kaslr_enabled()) {
  58                mutex_lock(&module_kaslr_mutex);
  59                /*
  60                 * Calculate the module_load_offset the first time this
  61                 * code is called. Once calculated it stays the same until
  62                 * reboot.
  63                 */
  64                if (module_load_offset == 0)
  65                        module_load_offset =
  66                                (get_random_int() % 1024 + 1) * PAGE_SIZE;
  67                mutex_unlock(&module_kaslr_mutex);
  68        }
  69        return module_load_offset;
  70}
  71#else
  72static unsigned long int get_module_load_offset(void)
  73{
  74        return 0;
  75}
  76#endif
  77
  78void *module_alloc(unsigned long size)
  79{
  80        void *p;
  81
  82        if (PAGE_ALIGN(size) > MODULES_LEN)
  83                return NULL;
  84
  85        p = __vmalloc_node_range(size, MODULE_ALIGN,
  86                                    MODULES_VADDR + get_module_load_offset(),
  87                                    MODULES_END, GFP_KERNEL | __GFP_HIGHMEM,
  88                                    PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
  89                                    __builtin_return_address(0));
  90        if (p && (kasan_module_alloc(p, size) < 0)) {
  91                vfree(p);
  92                return NULL;
  93        }
  94
  95        return p;
  96}
  97
  98#ifdef CONFIG_X86_32
  99int apply_relocate(Elf32_Shdr *sechdrs,
 100                   const char *strtab,
 101                   unsigned int symindex,
 102                   unsigned int relsec,
 103                   struct module *me)
 104{
 105        unsigned int i;
 106        Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
 107        Elf32_Sym *sym;
 108        uint32_t *location;
 109
 110        DEBUGP("Applying relocate section %u to %u\n",
 111               relsec, sechdrs[relsec].sh_info);
 112        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 113                /* This is where to make the change */
 114                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
 115                        + rel[i].r_offset;
 116                /* This is the symbol it is referring to.  Note that all
 117                   undefined symbols have been resolved.  */
 118                sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
 119                        + ELF32_R_SYM(rel[i].r_info);
 120
 121                switch (ELF32_R_TYPE(rel[i].r_info)) {
 122                case R_386_32:
 123                        /* We add the value into the location given */
 124                        *location += sym->st_value;
 125                        break;
 126                case R_386_PC32:
 127                        /* Add the value, subtract its position */
 128                        *location += sym->st_value - (uint32_t)location;
 129                        break;
 130                default:
 131                        pr_err("%s: Unknown relocation: %u\n",
 132                               me->name, ELF32_R_TYPE(rel[i].r_info));
 133                        return -ENOEXEC;
 134                }
 135        }
 136        return 0;
 137}
 138#else /*X86_64*/
 139int apply_relocate_add(Elf64_Shdr *sechdrs,
 140                   const char *strtab,
 141                   unsigned int symindex,
 142                   unsigned int relsec,
 143                   struct module *me)
 144{
 145        unsigned int i;
 146        Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
 147        Elf64_Sym *sym;
 148        void *loc;
 149        u64 val;
 150
 151        DEBUGP("Applying relocate section %u to %u\n",
 152               relsec, sechdrs[relsec].sh_info);
 153        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 154                /* This is where to make the change */
 155                loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
 156                        + rel[i].r_offset;
 157
 158                /* This is the symbol it is referring to.  Note that all
 159                   undefined symbols have been resolved.  */
 160                sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
 161                        + ELF64_R_SYM(rel[i].r_info);
 162
 163                DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
 164                       (int)ELF64_R_TYPE(rel[i].r_info),
 165                       sym->st_value, rel[i].r_addend, (u64)loc);
 166
 167                val = sym->st_value + rel[i].r_addend;
 168
 169                switch (ELF64_R_TYPE(rel[i].r_info)) {
 170                case R_X86_64_NONE:
 171                        break;
 172                case R_X86_64_64:
 173                        *(u64 *)loc = val;
 174                        break;
 175                case R_X86_64_32:
 176                        *(u32 *)loc = val;
 177                        if (val != *(u32 *)loc)
 178                                goto overflow;
 179                        break;
 180                case R_X86_64_32S:
 181                        *(s32 *)loc = val;
 182                        if ((s64)val != *(s32 *)loc)
 183                                goto overflow;
 184                        break;
 185                case R_X86_64_PC32:
 186                        val -= (u64)loc;
 187                        *(u32 *)loc = val;
 188#if 0
 189                        if ((s64)val != *(s32 *)loc)
 190                                goto overflow;
 191#endif
 192                        break;
 193                default:
 194                        pr_err("%s: Unknown rela relocation: %llu\n",
 195                               me->name, ELF64_R_TYPE(rel[i].r_info));
 196                        return -ENOEXEC;
 197                }
 198        }
 199        return 0;
 200
 201overflow:
 202        pr_err("overflow in relocation type %d val %Lx\n",
 203               (int)ELF64_R_TYPE(rel[i].r_info), val);
 204        pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
 205               me->name);
 206        return -ENOEXEC;
 207}
 208#endif
 209
 210int module_finalize(const Elf_Ehdr *hdr,
 211                    const Elf_Shdr *sechdrs,
 212                    struct module *me)
 213{
 214        const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
 215                *para = NULL;
 216        char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 217
 218        for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
 219                if (!strcmp(".text", secstrings + s->sh_name))
 220                        text = s;
 221                if (!strcmp(".altinstructions", secstrings + s->sh_name))
 222                        alt = s;
 223                if (!strcmp(".smp_locks", secstrings + s->sh_name))
 224                        locks = s;
 225                if (!strcmp(".parainstructions", secstrings + s->sh_name))
 226                        para = s;
 227        }
 228
 229        if (alt) {
 230                /* patch .altinstructions */
 231                void *aseg = (void *)alt->sh_addr;
 232                apply_alternatives(aseg, aseg + alt->sh_size);
 233        }
 234        if (locks && text) {
 235                void *lseg = (void *)locks->sh_addr;
 236                void *tseg = (void *)text->sh_addr;
 237                alternatives_smp_module_add(me, me->name,
 238                                            lseg, lseg + locks->sh_size,
 239                                            tseg, tseg + text->sh_size);
 240        }
 241
 242        if (para) {
 243                void *pseg = (void *)para->sh_addr;
 244                apply_paravirt(pseg, pseg + para->sh_size);
 245        }
 246
 247        /* make jump label nops */
 248        jump_label_apply_nops(me);
 249
 250        return 0;
 251}
 252
 253void module_arch_cleanup(struct module *mod)
 254{
 255        alternatives_smp_module_del(mod);
 256}
 257