blob: d60ca96b68db048012907c0e2dc744c3822a0414 [file] [log] [blame]
Lucas De Marchie701e382012-01-26 17:01:41 -02001/*
Lucas De Marchie6b0e492013-01-16 11:27:21 -02002 * Copyright (C) 2012-2013 ProFUSION embedded systems
Lucas De Marchie701e382012-01-26 17:01:41 -02003 *
Lucas De Marchie1b1ab22012-07-10 09:42:24 -03004 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
Lucas De Marchie701e382012-01-26 17:01:41 -02008 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Lucas De Marchie1b1ab22012-07-10 09:42:24 -030011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
Lucas De Marchie701e382012-01-26 17:01:41 -020013 *
Lucas De Marchie1b1ab22012-07-10 09:42:24 -030014 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Lucas De Marchie701e382012-01-26 17:01:41 -020017 */
18
Lucas De Marchi55112d12013-04-09 04:16:57 -030019#ifndef HAVE_FINIT_MODULE
20#define HAVE_FINIT_MODULE 1
21#endif
22
Lucas De Marchi53646fc2012-01-26 02:09:28 -020023#include <assert.h>
Lucas De Marchifca5b9b2012-06-21 11:30:56 -030024#include <elf.h>
Lucas De Marchi53646fc2012-01-26 02:09:28 -020025#include <errno.h>
26#include <dirent.h>
27#include <fcntl.h>
28#include <dlfcn.h>
29#include <limits.h>
30#include <stdlib.h>
31#include <stdarg.h>
32#include <stddef.h>
33#include <string.h>
34#include <stdio.h>
Kees Cooke87352d2013-02-18 12:02:33 -080035#include <sys/mman.h>
Lucas De Marchi53646fc2012-01-26 02:09:28 -020036#include <sys/types.h>
37#include <sys/stat.h>
38#include <unistd.h>
39
40/* kmod_elf_get_section() is not exported, we need the private header */
41#include <libkmod-private.h>
42
43/* FIXME: hack, change name so we don't clash */
44#undef ERR
Lucas De Marchi5a2949c2012-05-25 00:30:37 -030045#include "mkdir.h"
Lucas De Marchi53646fc2012-01-26 02:09:28 -020046#include "testsuite.h"
47#include "stripped-module.h"
48
49struct mod {
50 struct mod *next;
51 int ret;
52 int errcode;
53 char name[];
54};
55
56static struct mod *modules;
57static bool need_init = true;
Lucas De Marchia6553702012-06-05 00:53:15 -030058static struct kmod_ctx *ctx;
Lucas De Marchi53646fc2012-01-26 02:09:28 -020059
60static void parse_retcodes(struct mod *_modules, const char *s)
61{
62 const char *p;
63
64 if (s == NULL)
65 return;
66
67 for (p = s;;) {
68 struct mod *mod;
69 const char *modname;
70 char *end;
71 size_t modnamelen;
72 int ret, errcode;
73 long l;
74
75 modname = p;
76 if (modname == NULL || modname[0] == '\0')
77 break;
78
79 modnamelen = strcspn(s, ":");
80 if (modname[modnamelen] != ':')
81 break;
82
83 p = modname + modnamelen + 1;
84 if (p == NULL)
85 break;
86
87 l = strtol(p, &end, 0);
88 if (end == p || *end != ':')
89 break;
90 ret = (int) l;
91 p = end + 1;
92
93 l = strtol(p, &end, 0);
94 if (*end == ':')
95 p = end + 1;
96 else if (*end != '\0')
97 break;
98
99 errcode = (int) l;
100
101 mod = malloc(sizeof(*mod) + modnamelen + 1);
102 if (mod == NULL)
103 break;
104
105 memcpy(mod->name, modname, modnamelen);
106 mod->name[modnamelen] = '\0';
107 mod->ret = ret;
108 mod->errcode = errcode;
109 mod->next = _modules;
110 _modules = mod;
111 }
112}
113
Lucas De Marchi5a2949c2012-05-25 00:30:37 -0300114static int write_one_line_file(const char *fn, const char *line, int len)
115{
116 FILE *f;
117 int r;
118
119 assert(fn);
120 assert(line);
121
122 f = fopen(fn, "we");
123 if (!f)
124 return -errno;
125
126 errno = 0;
127 if (fputs(line, f) < 0) {
128 r = -errno;
129 goto finish;
130 }
131
132 fflush(f);
133
134 if (ferror(f)) {
135 if (errno != 0)
136 r = -errno;
137 else
138 r = -EIO;
139 } else
140 r = 0;
141
142finish:
143 fclose(f);
144 return r;
145}
146
147static int create_sysfs_files(const char *modname)
148{
149 char buf[PATH_MAX];
150 const char *sysfsmod = "/sys/module/";
151 int len = strlen(sysfsmod);
152
153 memcpy(buf, sysfsmod, len);
154 strcpy(buf + len, modname);
155 len += strlen(modname);
156
Lucas De Marchi33202e82012-06-19 13:09:23 -0300157 assert(mkdir_p(buf, 0755) >= 0);
Lucas De Marchi5a2949c2012-05-25 00:30:37 -0300158
159 strcpy(buf + len, "/initstate");
160 return write_one_line_file(buf, "live\n", strlen("live\n"));
161}
162
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200163static struct mod *find_module(struct mod *_modules, const char *modname)
164{
165 struct mod *mod;
166
167 for (mod = _modules; mod != NULL; mod = mod->next) {
Lucas De Marchi90fc4102012-06-05 00:07:38 -0300168 if (strcmp(mod->name, modname) == 0)
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200169 return mod;
170 }
171
172 return NULL;
173}
174
175static void init_retcodes(void)
176{
177 const char *s;
178
179 if (!need_init)
180 return;
181
182 need_init = false;
183 s = getenv(S_TC_INIT_MODULE_RETCODES);
184 if (s == NULL) {
185 fprintf(stderr, "TRAP init_module(): missing export %s?\n",
186 S_TC_INIT_MODULE_RETCODES);
187 }
188
Lucas De Marchia6553702012-06-05 00:53:15 -0300189 ctx = kmod_new(NULL, NULL);
190
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200191 parse_retcodes(modules, s);
192}
193
Lucas De Marchia6553702012-06-05 00:53:15 -0300194static inline bool module_is_inkernel(const char *modname)
195{
196 struct kmod_module *mod;
197 int state;
198 bool ret;
199
200 if (kmod_module_new_from_name(ctx, modname, &mod) < 0)
201 return false;
202
203 state = kmod_module_get_initstate(mod);
204
205 if (state == KMOD_MODULE_LIVE ||
206 state == KMOD_MODULE_BUILTIN)
207 ret = true;
208 else
209 ret = false;
210
211 kmod_module_unref(mod);
212
213 return ret;
214}
215
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300216static uint8_t elf_identify(void *mem)
217{
218 uint8_t *p = mem;
219 return p[EI_CLASS];
220}
221
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200222TS_EXPORT long init_module(void *mem, unsigned long len, const char *args);
223
224/*
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300225 * Default behavior is to try to mimic init_module behavior inside the kernel.
226 * If it is a simple test that you know the error code, set the return code
227 * in TESTSUITE_INIT_MODULE_RETCODES env var instead.
228 *
229 * The exception is when the module name is not find in the memory passed.
230 * This is because we want to be able to pass dummy modules (and not real
231 * ones) and it still work.
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200232 */
233long init_module(void *mem, unsigned long len, const char *args)
234{
235 const char *modname;
236 struct kmod_elf *elf;
237 struct mod *mod;
238 const void *buf;
239 uint64_t bufsize;
240 int err;
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300241 uint8_t class;
242 off_t offset;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200243
244 init_retcodes();
245
246 elf = kmod_elf_new(mem, len);
247 if (elf == NULL)
248 return 0;
249
250 err = kmod_elf_get_section(elf, ".gnu.linkonce.this_module", &buf,
251 &bufsize);
252 kmod_elf_unref(elf);
253
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300254 /* We couldn't parse the ELF file. Just exit as if it was successful */
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200255 if (err < 0)
256 return 0;
257
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300258 /* We need to open both 32 and 64 bits module - hack! */
259 class = elf_identify(mem);
260 if (class == ELFCLASS64)
261 offset = MODULE_NAME_OFFSET_64;
262 else
263 offset = MODULE_NAME_OFFSET_32;
264
265 modname = (char *)buf + offset;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200266 mod = find_module(modules, modname);
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300267 if (mod != NULL) {
268 errno = mod->errcode;
269 err = mod->ret;
Lucas De Marchia6553702012-06-05 00:53:15 -0300270 } else if (module_is_inkernel(modname)) {
271 err = -1;
272 errno = EEXIST;
273 } else
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300274 err = 0;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200275
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300276 if (err == 0)
277 create_sysfs_files(modname);
278
279 return err;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200280}
281
Kees Cooke87352d2013-02-18 12:02:33 -0800282TS_EXPORT int finit_module(const int fd, const char *args, const int flags);
283
284int finit_module(const int fd, const char *args, const int flags)
285{
286 int err;
287 void *mem;
288 unsigned long len;
289 struct stat st;
290
291 if (fstat(fd, &st) < 0)
292 return -1;
293
294 len = st.st_size;
295 mem = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
296 if (mem == MAP_FAILED)
297 return -1;
298
299 err = init_module(mem, len, args);
300 munmap(mem, len);
301
302 return err;
303}
304
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200305/* the test is going away anyway, but lets keep valgrind happy */
306void free_resources(void) __attribute__((destructor));
307void free_resources(void)
308{
309 while (modules) {
310 struct mod *mod = modules->next;
311 free(modules);
312 modules = mod;
313 }
Lucas De Marchia6553702012-06-05 00:53:15 -0300314
315 if (ctx)
316 kmod_unref(ctx);
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200317}