Home | History | Annotate | Download | only in module
      1 /*
      2  * common.c
      3  *
      4  *  Created on: Aug 11, 2008
      5  *      Author: Stefan Bucur <stefanb (at) zytor.com>
      6  */
      7 
      8 #include <stdio.h>
      9 #include <elf.h>
     10 #include <string.h>
     11 #include <fs.h>
     12 
     13 #include <linux/list.h>
     14 #include <sys/module.h>
     15 
     16 #include "elfutils.h"
     17 #include "common.h"
     18 
     19 /**
     20  * The one and only list of loaded modules
     21  */
     22 LIST_HEAD(modules_head);
     23 
     24 // User-space debugging routines
     25 #ifdef ELF_DEBUG
     26 void print_elf_ehdr(Elf_Ehdr *ehdr) {
     27 	int i;
     28 
     29 	fprintf(stderr, "Identification:\t");
     30 	for (i=0; i < EI_NIDENT; i++) {
     31 		printf("%d ", ehdr->e_ident[i]);
     32 	}
     33 	fprintf(stderr, "\n");
     34 	fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
     35 	fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
     36 	fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
     37 	fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
     38 	fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
     39 	fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
     40 	//fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
     41 	//fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf_Ehdr));
     42 	fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
     43 		ehdr->e_shnum);
     44 }
     45 
     46 void print_elf_symbols(struct elf_module *module) {
     47 	unsigned int i;
     48 	Elf_Sym *crt_sym;
     49 
     50 	for (i = 1; i < module->symtable_size/module->syment_size; i++)
     51 	{
     52 		crt_sym = (Elf_Sym*)(module->sym_table + i*module->syment_size);
     53 
     54 		fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
     55 
     56 	}
     57 }
     58 #endif //ELF_DEBUG
     59 
     60 FILE *findpath(char *name)
     61 {
     62 	struct path_entry *entry;
     63 	char path[FILENAME_MAX];
     64 	FILE *f;
     65 
     66 	f = fopen(name, "rb"); /* for full path */
     67 	if (f)
     68 		return f;
     69 
     70 	list_for_each_entry(entry, &PATH, list) {
     71 		bool slash = false;
     72 
     73 		/* Ensure we have a '/' separator */
     74 		if (entry->str[strlen(entry->str) - 1] != '/')
     75 			slash = true;
     76 
     77 		snprintf(path, sizeof(path), "%s%s%s",
     78 			 entry->str, slash ? "/" : "", name);
     79 
     80 		dprintf("findpath: trying \"%s\"\n", path);
     81 		f = fopen(path, "rb");
     82 		if (f)
     83 			return f;
     84 	}
     85 
     86 	return NULL;
     87 }
     88 
     89 /*
     90  * Image files manipulation routines
     91  */
     92 
     93 int image_load(struct elf_module *module)
     94 {
     95 	module->u.l._file = findpath(module->name);
     96 
     97 	if (module->u.l._file == NULL) {
     98 		dprintf("Could not open object file '%s'\n", module->name);
     99 		goto error;
    100 	}
    101 
    102 	module->u.l._cr_offset = 0;
    103 
    104 	return 0;
    105 
    106 error:
    107 	if (module->u.l._file != NULL) {
    108 		fclose(module->u.l._file);
    109 		module->u.l._file = NULL;
    110 	}
    111 
    112 	return -1;
    113 }
    114 
    115 
    116 int image_unload(struct elf_module *module) {
    117 	if (module->u.l._file != NULL) {
    118 		fclose(module->u.l._file);
    119 		module->u.l._file = NULL;
    120 
    121 	}
    122 	module->u.l._cr_offset = 0;
    123 
    124 	return 0;
    125 }
    126 
    127 int image_read(void *buff, size_t size, struct elf_module *module) {
    128 	size_t result = fread(buff, size, 1, module->u.l._file);
    129 
    130 	if (result < 1)
    131 		return -1;
    132 
    133 	module->u.l._cr_offset += size;
    134 	return 0;
    135 }
    136 
    137 int image_skip(size_t size, struct elf_module *module) {
    138 	void *skip_buff = NULL;
    139 	size_t result;
    140 
    141 	if (size == 0)
    142 		return 0;
    143 
    144 	skip_buff = malloc(size);
    145 	result = fread(skip_buff, size, 1, module->u.l._file);
    146 	free(skip_buff);
    147 
    148 	if (result < 1)
    149 		return -1;
    150 
    151 	module->u.l._cr_offset += size;
    152 	return 0;
    153 }
    154 
    155 int image_seek(Elf_Off offset, struct elf_module *module) {
    156 	if (offset < module->u.l._cr_offset) // Cannot seek backwards
    157 		return -1;
    158 
    159 	return image_skip(offset - module->u.l._cr_offset, module);
    160 }
    161 
    162 
    163 // Initialization of the module subsystem
    164 int modules_init(void) {
    165 	return 0;
    166 }
    167 
    168 // Termination of the module subsystem
    169 void modules_term(void) {
    170 
    171 }
    172 
    173 // Allocates the structure for a new module
    174 struct elf_module *module_alloc(const char *name) {
    175 	struct elf_module *result = malloc(sizeof(struct elf_module));
    176 
    177 	if (!result) {
    178 	    dprintf("module: Failed to alloc elf_module\n");
    179 	    return NULL;
    180 	}
    181 
    182 	memset(result, 0, sizeof(struct elf_module));
    183 
    184 	INIT_LIST_HEAD(&result->list);
    185 	INIT_LIST_HEAD(&result->required);
    186 	INIT_LIST_HEAD(&result->dependants);
    187 
    188 	strncpy(result->name, name, MODULE_NAME_SIZE);
    189 
    190 	return result;
    191 }
    192 
    193 struct module_dep *module_dep_alloc(struct elf_module *module) {
    194 	struct module_dep *result = malloc(sizeof(struct module_dep));
    195 
    196 	INIT_LIST_HEAD (&result->list);
    197 
    198 	result->module = module;
    199 
    200 	return result;
    201 }
    202 
    203 struct elf_module *module_find(const char *name) {
    204 	struct elf_module *cr_module;
    205 
    206 	for_each_module(cr_module) {
    207 		if (strcmp(cr_module->name, name) == 0)
    208 			return cr_module;
    209 	}
    210 
    211 	return NULL;
    212 }
    213 
    214 
    215 // Mouli: This is checking the header for 32bit machine
    216 // Support 64bit architecture as well.
    217 // Parts of the ELF header checked are common to both ELF32 and ELF64
    218 // Adding simple checks for both 32bit and 64bit should work (hopefully)
    219 //
    220 // Performs verifications on ELF header to assure that the open file is a
    221 // valid SYSLINUX ELF module.
    222 int check_header_common(Elf_Ehdr *elf_hdr) {
    223 	// Check the header magic
    224 	if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
    225 		elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
    226 		elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
    227 		elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
    228 
    229 		dprintf("The file is not an ELF object\n");
    230 		return -1;
    231 	}
    232 
    233 	if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 &&
    234 	    elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) {
    235 		dprintf("Invalid ELF class code\n");
    236 		return -1;
    237 	}
    238 
    239 	if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
    240 		dprintf("Invalid ELF data encoding\n");
    241 		return -1;
    242 	}
    243 
    244 	if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
    245 			elf_hdr->e_version != MODULE_ELF_VERSION) {
    246 		dprintf("Invalid ELF file version\n");
    247 		return -1;
    248 	}
    249 
    250 	if (elf_hdr->e_machine != EM_386 &&
    251 		elf_hdr->e_machine != EM_X86_64) {
    252 		dprintf("Invalid ELF architecture\n");
    253 		return -1;
    254 	}
    255 
    256 	return 0;
    257 }
    258 
    259 
    260 
    261 int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
    262 	struct module_dep *crt_dep;
    263 	struct module_dep *new_dep;
    264 
    265 	list_for_each_entry(crt_dep, &req->dependants, list) {
    266 		if (crt_dep->module == dep) {
    267 			// The dependency is already enforced
    268 			return 0;
    269 		}
    270 	}
    271 
    272 	new_dep = module_dep_alloc(req);
    273 	list_add(&new_dep->list, &dep->required);
    274 
    275 	new_dep = module_dep_alloc(dep);
    276 	list_add(&new_dep->list, &req->dependants);
    277 
    278 	return 0;
    279 }
    280 
    281 int clear_dependency(struct elf_module *req, struct elf_module *dep) {
    282 	struct module_dep *crt_dep = NULL;
    283 	int found = 0;
    284 
    285 	list_for_each_entry(crt_dep, &req->dependants, list) {
    286 		if (crt_dep->module == dep) {
    287 			found = 1;
    288 			break;
    289 		}
    290 	}
    291 
    292 	if (found) {
    293 		list_del(&crt_dep->list);
    294 		free(crt_dep);
    295 	}
    296 
    297 	found = 0;
    298 
    299 	list_for_each_entry(crt_dep, &dep->required, list) {
    300 		if (crt_dep->module == req) {
    301 			found = 1;
    302 			break;
    303 		}
    304 	}
    305 
    306 	if (found) {
    307 		list_del(&crt_dep->list);
    308 		free(crt_dep);
    309 	}
    310 
    311 	return 0;
    312 }
    313 
    314 int check_symbols(struct elf_module *module)
    315 {
    316 	unsigned int i;
    317 	Elf_Sym *crt_sym = NULL, *ref_sym = NULL;
    318 	char *crt_name;
    319 	struct elf_module *crt_module;
    320 
    321 	int strong_count;
    322 	int weak_count;
    323 
    324 	for (i = 1; i < module->symtable_size/module->syment_size; i++)
    325 	{
    326 		crt_sym = symbol_get_entry(module, i);
    327 		crt_name = module->str_table + crt_sym->st_name;
    328 
    329 		strong_count = 0;
    330 		weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
    331 
    332 		for_each_module(crt_module)
    333 		{
    334 			ref_sym = module_find_symbol(crt_name, crt_module);
    335 
    336 			// If we found a definition for our symbol...
    337 			if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
    338 			{
    339 				switch (ELF32_ST_BIND(ref_sym->st_info))
    340 				{
    341 					case STB_GLOBAL:
    342 						strong_count++;
    343 						break;
    344 					case STB_WEAK:
    345 						weak_count++;
    346 						break;
    347 				}
    348 			}
    349 		}
    350 
    351 		if (crt_sym->st_shndx == SHN_UNDEF)
    352 		{
    353 			// We have an undefined symbol
    354 			//
    355 			// We use the weak_count to differentiate
    356 			// between Syslinux-derivative-specific
    357 			// functions. For example, unload_pxe() is
    358 			// only provided by PXELINUX, so we mark it as
    359 			// __weak and replace it with a reference to
    360 			// undefined_symbol() on SYSLINUX, EXTLINUX,
    361 			// and ISOLINUX. See perform_relocations().
    362 			if (strong_count == 0 && weak_count == 0)
    363 			{
    364 				dprintf("Symbol %s is undefined\n", crt_name);
    365 				printf("Undef symbol FAIL: %s\n",crt_name);
    366 				return -1;
    367 			}
    368 		}
    369 		else
    370 		{
    371 			if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
    372 			{
    373 				// It's not an error - at relocation, the most recent symbol
    374 				// will be considered
    375 				dprintf("Info: Symbol %s is defined more than once\n", crt_name);
    376 			}
    377 		}
    378 		//printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
    379 	}
    380 
    381 	return 0;
    382 }
    383 
    384 int module_unloadable(struct elf_module *module) {
    385 	if (!list_empty(&module->dependants))
    386 		return 0;
    387 
    388 	return 1;
    389 }
    390 
    391 
    392 // Unloads the module from the system and releases all the associated memory
    393 int _module_unload(struct elf_module *module) {
    394 	struct module_dep *crt_dep, *tmp;
    395 	// Make sure nobody needs us
    396 	if (!module_unloadable(module)) {
    397 		dprintf("Module is required by other modules.\n");
    398 		return -1;
    399 	}
    400 
    401 	// Remove any dependency information
    402 	list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
    403 		clear_dependency(crt_dep->module, module);
    404 	}
    405 
    406 	// Remove the module from the module list
    407 	list_del_init(&module->list);
    408 
    409 	// Release the loaded segments or sections
    410 	if (module->module_addr != NULL) {
    411 		elf_free(module->module_addr);
    412 
    413 		dprintf("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
    414 				module->name);
    415 	}
    416 
    417 	dprintf("Unloading module %s\n", module->name);
    418 	// Release the module structure
    419 	free(module);
    420 
    421 	return 0;
    422 }
    423 
    424 int module_unload(struct elf_module *module) {
    425 	module_ctor_t *dtor;
    426 
    427 	for (dtor = module->dtors; dtor && *dtor; dtor++)
    428 		(*dtor) ();
    429 
    430 	return _module_unload(module);
    431 }
    432 
    433 struct elf_module *unload_modules_since(const char *name) {
    434 	struct elf_module *m, *mod, *begin = NULL;
    435 
    436 	for_each_module(mod) {
    437 		if (!strcmp(mod->name, name)) {
    438 			begin = mod;
    439 			break;
    440 		}
    441 	}
    442 
    443 	if (!begin)
    444 		return begin;
    445 
    446 	for_each_module_safe(mod, m) {
    447 		if (mod == begin)
    448 			break;
    449 
    450 		if (mod != begin)
    451 			module_unload(mod);
    452 	}
    453 
    454 	return begin;
    455 }
    456 
    457 static Elf_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
    458 	unsigned long h = elf_hash((const unsigned char*)name);
    459 	Elf_Word *cr_word = module->hash_table;
    460 
    461 	Elf_Word nbucket = *cr_word++;
    462 	cr_word++; // Skip nchain
    463 
    464 	Elf_Word *bkt = cr_word;
    465 	Elf_Word *chn = cr_word + nbucket;
    466 
    467 	Elf_Word crt_index = bkt[h % module->hash_table[0]];
    468 	Elf_Sym *crt_sym;
    469 
    470 
    471 	while (crt_index != STN_UNDEF) {
    472 		crt_sym = symbol_get_entry(module, crt_index);
    473 
    474 		if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
    475 			return crt_sym;
    476 
    477 		crt_index = chn[crt_index];
    478 	}
    479 
    480 	return NULL;
    481 }
    482 
    483 static Elf_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
    484 	unsigned long h = elf_gnu_hash((const unsigned char*)name);
    485 
    486 	// Setup code (TODO: Optimize this by computing only once)
    487 	Elf_Word *cr_word = module->ghash_table;
    488 	Elf_Word nbucket = *cr_word++;
    489 	Elf_Word symbias = *cr_word++;
    490 	Elf_Word bitmask_nwords = *cr_word++;
    491 
    492 	if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
    493 		dprintf("Invalid GNU Hash structure\n");
    494 		return NULL;
    495 	}
    496 
    497 	Elf_Word gnu_shift = *cr_word++;
    498 
    499 	Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word;
    500 	cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
    501 
    502 	Elf_Word *gnu_buckets = cr_word;
    503 	cr_word += nbucket;
    504 
    505 	Elf_Word *gnu_chain_zero = cr_word - symbias;
    506 
    507 	// Computations
    508 	Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
    509 	                                       (bitmask_nwords - 1)];
    510 
    511 	unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
    512 	unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
    513 
    514 	if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
    515 		unsigned long rem;
    516 		Elf_Word bucket;
    517 
    518 		rem = h % nbucket;
    519 
    520 		bucket = gnu_buckets[rem];
    521 
    522 		if (bucket != 0) {
    523 			const Elf_Word* hasharr = &gnu_chain_zero[bucket];
    524 
    525 			do {
    526 				if (((*hasharr ^ h ) >> 1) == 0) {
    527 					Elf_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
    528 
    529 					if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
    530 						return crt_sym;
    531 					}
    532 				}
    533 			} while ((*hasharr++ & 1u) == 0);
    534 		}
    535 	}
    536 
    537 	return NULL;
    538 }
    539 
    540 static Elf_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
    541 {
    542 
    543 	unsigned int i;
    544 	Elf_Sym *crt_sym;
    545 
    546 	for (i = 1; i < module->symtable_size/module->syment_size; i++)
    547 	{
    548 		crt_sym = symbol_get_entry(module, i);
    549 		if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
    550 		{
    551 			return crt_sym;
    552 		}
    553 	}
    554 
    555 	return NULL;
    556 }
    557 
    558 Elf_Sym *module_find_symbol(const char *name, struct elf_module *module) {
    559 	Elf_Sym *result = NULL;
    560 
    561 	if (module->ghash_table != NULL)
    562 		result = module_find_symbol_gnu(name, module);
    563 
    564 	if (result == NULL)
    565 	{
    566 		if (module->hash_table != NULL)
    567 		{
    568 			//printf("Attempting SYSV Symbol search\n");
    569 			result = module_find_symbol_sysv(name, module);
    570 		}
    571 		else
    572 		{
    573 			//printf("Attempting Iterative Symbol search\n");
    574 			result = module_find_symbol_iterate(name, module);
    575 		}
    576 	}
    577 
    578 	return result;
    579 }
    580 
    581 Elf_Sym *global_find_symbol(const char *name, struct elf_module **module) {
    582 	struct elf_module *crt_module;
    583 	Elf_Sym *crt_sym = NULL;
    584 	Elf_Sym *result = NULL;
    585 
    586 	for_each_module(crt_module) {
    587 		crt_sym = module_find_symbol(name, crt_module);
    588 
    589 		if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
    590 			switch (ELF32_ST_BIND(crt_sym->st_info)) {
    591 			case STB_GLOBAL:
    592 				if (module != NULL) {
    593 					*module = crt_module;
    594 				}
    595 				return crt_sym;
    596 			case STB_WEAK:
    597 				// Consider only the first weak symbol
    598 				if (result == NULL) {
    599 					if (module != NULL) {
    600 						*module = crt_module;
    601 					}
    602 					result = crt_sym;
    603 				}
    604 				break;
    605 			}
    606 		}
    607 	}
    608 
    609 	return result;
    610 }
    611