Home | History | Annotate | Download | only in testsuite
      1 /*
      2  * Copyright (C) 2012-2013  ProFUSION embedded systems
      3  * Copyright (C) 2012-2013  Lucas De Marchi <lucas.de.marchi (at) gmail.com>
      4  *
      5  * This program is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Lesser General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2.1 of the License, or (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Lesser General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Lesser General Public
     16  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #ifndef HAVE_FINIT_MODULE
     20 #define HAVE_FINIT_MODULE 1
     21 #endif
     22 
     23 #include <assert.h>
     24 #include <dirent.h>
     25 #include <dlfcn.h>
     26 #include <elf.h>
     27 #include <errno.h>
     28 #include <fcntl.h>
     29 #include <limits.h>
     30 #include <stdarg.h>
     31 #include <stddef.h>
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <unistd.h>
     36 #include <sys/mman.h>
     37 #include <sys/stat.h>
     38 #include <sys/syscall.h>
     39 #include <sys/types.h>
     40 #include <sys/utsname.h>
     41 
     42 #include <shared/util.h>
     43 
     44 /* kmod_elf_get_section() is not exported, we need the private header */
     45 #include <libkmod/libkmod-internal.h>
     46 
     47 /* FIXME: hack, change name so we don't clash */
     48 #undef ERR
     49 #include "testsuite.h"
     50 #include "stripped-module.h"
     51 
     52 struct mod {
     53 	struct mod *next;
     54 	int ret;
     55 	int errcode;
     56 	char name[];
     57 };
     58 
     59 static struct mod *modules;
     60 static bool need_init = true;
     61 static struct kmod_ctx *ctx;
     62 
     63 static void parse_retcodes(struct mod *_modules, const char *s)
     64 {
     65 	const char *p;
     66 
     67 	if (s == NULL)
     68 		return;
     69 
     70 	for (p = s;;) {
     71 		struct mod *mod;
     72 		const char *modname;
     73 		char *end;
     74 		size_t modnamelen;
     75 		int ret, errcode;
     76 		long l;
     77 
     78 		modname = p;
     79 		if (modname == NULL || modname[0] == '\0')
     80 			break;
     81 
     82 		modnamelen = strcspn(s, ":");
     83 		if (modname[modnamelen] != ':')
     84 			break;
     85 
     86 		p = modname + modnamelen + 1;
     87 		if (p == NULL)
     88 			break;
     89 
     90 		l = strtol(p, &end, 0);
     91 		if (end == p || *end != ':')
     92 			break;
     93 		ret = (int) l;
     94 		p = end + 1;
     95 
     96 		l = strtol(p, &end, 0);
     97 		if (*end == ':')
     98 			p = end + 1;
     99 		else if (*end != '\0')
    100 			break;
    101 
    102 		errcode = (int) l;
    103 
    104 		mod = malloc(sizeof(*mod) + modnamelen + 1);
    105 		if (mod == NULL)
    106 			break;
    107 
    108 		memcpy(mod->name, modname, modnamelen);
    109 		mod->name[modnamelen] = '\0';
    110 		mod->ret = ret;
    111 		mod->errcode = errcode;
    112 		mod->next = _modules;
    113 		_modules = mod;
    114 	}
    115 }
    116 
    117 static int write_one_line_file(const char *fn, const char *line, int len)
    118 {
    119         FILE *f;
    120         int r;
    121 
    122         assert(fn);
    123         assert(line);
    124 
    125         f = fopen(fn, "we");
    126         if (!f)
    127                 return -errno;
    128 
    129         errno = 0;
    130         if (fputs(line, f) < 0) {
    131                 r = -errno;
    132                 goto finish;
    133         }
    134 
    135         fflush(f);
    136 
    137         if (ferror(f)) {
    138                 if (errno != 0)
    139                         r = -errno;
    140                 else
    141                         r = -EIO;
    142         } else
    143                 r = 0;
    144 
    145 finish:
    146         fclose(f);
    147         return r;
    148 }
    149 
    150 static int create_sysfs_files(const char *modname)
    151 {
    152 	char buf[PATH_MAX];
    153 	const char *sysfsmod = "/sys/module/";
    154 	int len = strlen(sysfsmod);
    155 
    156 	memcpy(buf, sysfsmod, len);
    157 	strcpy(buf + len, modname);
    158 	len += strlen(modname);
    159 
    160 	assert(mkdir_p(buf, len, 0755) >= 0);
    161 
    162 	strcpy(buf + len, "/initstate");
    163 	return write_one_line_file(buf, "live\n", strlen("live\n"));
    164 }
    165 
    166 static struct mod *find_module(struct mod *_modules, const char *modname)
    167 {
    168 	struct mod *mod;
    169 
    170 	for (mod = _modules; mod != NULL; mod = mod->next) {
    171 		if (streq(mod->name, modname))
    172 			return mod;
    173 	}
    174 
    175 	return NULL;
    176 }
    177 
    178 static void init_retcodes(void)
    179 {
    180 	const char *s;
    181 
    182 	if (!need_init)
    183 		return;
    184 
    185 	need_init = false;
    186 	s = getenv(S_TC_INIT_MODULE_RETCODES);
    187 	if (s == NULL) {
    188 		fprintf(stderr, "TRAP init_module(): missing export %s?\n",
    189 						S_TC_INIT_MODULE_RETCODES);
    190 	}
    191 
    192 	ctx = kmod_new(NULL, NULL);
    193 
    194 	parse_retcodes(modules, s);
    195 }
    196 
    197 static inline bool module_is_inkernel(const char *modname)
    198 {
    199 	struct kmod_module *mod;
    200 	int state;
    201 	bool ret;
    202 
    203 	if (kmod_module_new_from_name(ctx, modname, &mod) < 0)
    204 		return false;
    205 
    206 	state = kmod_module_get_initstate(mod);
    207 
    208 	if (state == KMOD_MODULE_LIVE ||
    209 			state == KMOD_MODULE_BUILTIN)
    210 		ret = true;
    211 	else
    212 		ret = false;
    213 
    214 	kmod_module_unref(mod);
    215 
    216 	return ret;
    217 }
    218 
    219 static uint8_t elf_identify(void *mem)
    220 {
    221 	uint8_t *p = mem;
    222 	return p[EI_CLASS];
    223 }
    224 
    225 TS_EXPORT long init_module(void *mem, unsigned long len, const char *args);
    226 
    227 /*
    228  * Default behavior is to try to mimic init_module behavior inside the kernel.
    229  * If it is a simple test that you know the error code, set the return code
    230  * in TESTSUITE_INIT_MODULE_RETCODES env var instead.
    231  *
    232  * The exception is when the module name is not find in the memory passed.
    233  * This is because we want to be able to pass dummy modules (and not real
    234  * ones) and it still work.
    235  */
    236 long init_module(void *mem, unsigned long len, const char *args)
    237 {
    238 	const char *modname;
    239 	struct kmod_elf *elf;
    240 	struct mod *mod;
    241 	const void *buf;
    242 	uint64_t bufsize;
    243 	int err;
    244 	uint8_t class;
    245 	off_t offset;
    246 
    247 	init_retcodes();
    248 
    249 	elf = kmod_elf_new(mem, len);
    250 	if (elf == NULL)
    251 		return 0;
    252 
    253 	err = kmod_elf_get_section(elf, ".gnu.linkonce.this_module", &buf,
    254 								&bufsize);
    255 	kmod_elf_unref(elf);
    256 
    257 	/* We couldn't parse the ELF file. Just exit as if it was successful */
    258 	if (err < 0)
    259 		return 0;
    260 
    261 	/* We need to open both 32 and 64 bits module - hack! */
    262 	class = elf_identify(mem);
    263 	if (class == ELFCLASS64)
    264 		offset = MODULE_NAME_OFFSET_64;
    265 	else
    266 		offset = MODULE_NAME_OFFSET_32;
    267 
    268 	modname = (char *)buf + offset;
    269 	mod = find_module(modules, modname);
    270 	if (mod != NULL) {
    271 		errno = mod->errcode;
    272 		err = mod->ret;
    273 	} else if (module_is_inkernel(modname)) {
    274 		err = -1;
    275 		errno = EEXIST;
    276 	} else
    277 		err = 0;
    278 
    279 	if (err == 0)
    280 		create_sysfs_files(modname);
    281 
    282 	return err;
    283 }
    284 
    285 static int check_kernel_version(int major, int minor)
    286 {
    287 	struct utsname u;
    288 	const char *p;
    289 	int maj = 0, min = 0;
    290 
    291 	if (uname(&u) < 0)
    292 		return false;
    293 	for (p = u.release; *p >= '0' && *p <= '9'; p++)
    294 		maj = maj * 10 + *p - '0';
    295 	if (*p == '.')
    296 		for (p++; *p >= '0' && *p <= '9'; p++)
    297 			min = min * 10 + *p - '0';
    298 	if (maj > major || (maj == major && min >= minor))
    299 		return true;
    300 	return false;
    301 }
    302 
    303 
    304 TS_EXPORT int finit_module(const int fd, const char *args, const int flags);
    305 
    306 int finit_module(const int fd, const char *args, const int flags)
    307 {
    308 	int err;
    309 	void *mem;
    310 	unsigned long len;
    311 	struct stat st;
    312 
    313 	if (!check_kernel_version(3, 8)) {
    314 		errno = ENOSYS;
    315 		return -1;
    316 	}
    317 	if (fstat(fd, &st) < 0)
    318 		return -1;
    319 
    320 	len = st.st_size;
    321 	mem = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
    322 	if (mem == MAP_FAILED)
    323 		return -1;
    324 
    325 	err = init_module(mem, len, args);
    326 	munmap(mem, len);
    327 
    328 	return err;
    329 }
    330 
    331 TS_EXPORT long int syscall(long int __sysno, ...)
    332 {
    333 	va_list ap;
    334 	long ret;
    335 
    336 	if (__sysno == -1) {
    337 		errno = ENOSYS;
    338 		return -1;
    339 	}
    340 
    341 	if (__sysno == __NR_finit_module) {
    342 		const char *args;
    343 		int flags;
    344 		int fd;
    345 
    346 		va_start(ap, __sysno);
    347 
    348 		fd = va_arg(ap, int);
    349 		args = va_arg(ap, const char *);
    350 		flags = va_arg(ap, int);
    351 
    352 		ret = finit_module(fd, args, flags);
    353 
    354 		va_end(ap);
    355 		return ret;
    356 	}
    357 
    358 	/*
    359 	 * FIXME: no way to call the libc function - let's hope there are no
    360 	 * other users.
    361 	 */
    362 	abort();
    363 }
    364 
    365 /* the test is going away anyway, but lets keep valgrind happy */
    366 void free_resources(void) __attribute__((destructor));
    367 void free_resources(void)
    368 {
    369 	while (modules) {
    370 		struct mod *mod = modules->next;
    371 		free(modules);
    372 		modules = mod;
    373 	}
    374 
    375 	if (ctx)
    376 		kmod_unref(ctx);
    377 }
    378