• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2012-2013  ProFUSION embedded systems
3   * Copyright (C) 2012-2013  Lucas De Marchi <lucas.de.marchi@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  
parse_retcodes(struct mod * _modules,const char * s)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  
write_one_line_file(const char * fn,const char * line,int len)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  
create_sysfs_files(const char * modname)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  
find_module(struct mod * _modules,const char * modname)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  
init_retcodes(void)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  
module_is_inkernel(const char * modname)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  
elf_identify(void * mem)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   */
init_module(void * mem,unsigned long len,const char * args)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  
check_kernel_version(int major,int minor)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  
finit_module(const int fd,const char * args,const int flags)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  
syscall(long int __sysno,...)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));
free_resources(void)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