1e701e381faac8977f472b881d426335b869998dcLucas De Marchi/*
2e6b0e49b4ea7937a98b16f23d621244ee1a3e588Lucas De Marchi * Copyright (C) 2012-2013  ProFUSION embedded systems
30ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi * Copyright (C) 2012-2013  Lucas De Marchi <lucas.de.marchi@gmail.com>
4e701e381faac8977f472b881d426335b869998dcLucas De Marchi *
5e1b1ab24ab7b690343dbddd8087b17f6d722327cLucas De Marchi * This program is free software; you can redistribute it and/or
6e1b1ab24ab7b690343dbddd8087b17f6d722327cLucas De Marchi * modify it under the terms of the GNU Lesser General Public
7e1b1ab24ab7b690343dbddd8087b17f6d722327cLucas De Marchi * License as published by the Free Software Foundation; either
8e1b1ab24ab7b690343dbddd8087b17f6d722327cLucas De Marchi * version 2.1 of the License, or (at your option) any later version.
9e701e381faac8977f472b881d426335b869998dcLucas De Marchi *
10e701e381faac8977f472b881d426335b869998dcLucas De Marchi * This program is distributed in the hope that it will be useful,
11e701e381faac8977f472b881d426335b869998dcLucas De Marchi * but WITHOUT ANY WARRANTY; without even the implied warranty of
12e1b1ab24ab7b690343dbddd8087b17f6d722327cLucas De Marchi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13e1b1ab24ab7b690343dbddd8087b17f6d722327cLucas De Marchi * Lesser General Public License for more details.
14e701e381faac8977f472b881d426335b869998dcLucas De Marchi *
15e1b1ab24ab7b690343dbddd8087b17f6d722327cLucas De Marchi * You should have received a copy of the GNU Lesser General Public
16dea2dfee9b301da84dbb09cf510b8ebf2ef28fffLucas De Marchi * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17e701e381faac8977f472b881d426335b869998dcLucas De Marchi */
18e701e381faac8977f472b881d426335b869998dcLucas De Marchi
1955112d19f7067dff89b1481d5bd8cc49139c4ecbLucas De Marchi#ifndef HAVE_FINIT_MODULE
2055112d19f7067dff89b1481d5bd8cc49139c4ecbLucas De Marchi#define HAVE_FINIT_MODULE 1
2155112d19f7067dff89b1481d5bd8cc49139c4ecbLucas De Marchi#endif
2255112d19f7067dff89b1481d5bd8cc49139c4ecbLucas De Marchi
2353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <assert.h>
24c2e4286bb98c6bec77575ac0c6f862e7ddf6394fLucas De Marchi#include <dirent.h>
25c2e4286bb98c6bec77575ac0c6f862e7ddf6394fLucas De Marchi#include <dlfcn.h>
26fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi#include <elf.h>
2753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <errno.h>
2853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <fcntl.h>
2953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <limits.h>
3053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <stdarg.h>
3153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <stddef.h>
3253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <stdio.h>
33c2e4286bb98c6bec77575ac0c6f862e7ddf6394fLucas De Marchi#include <stdlib.h>
34c2e4286bb98c6bec77575ac0c6f862e7ddf6394fLucas De Marchi#include <string.h>
35c2e4286bb98c6bec77575ac0c6f862e7ddf6394fLucas De Marchi#include <unistd.h>
36e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook#include <sys/mman.h>
3753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include <sys/stat.h>
380ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi#include <sys/syscall.h>
39c2e4286bb98c6bec77575ac0c6f862e7ddf6394fLucas De Marchi#include <sys/types.h>
40063086e038657de64f9980bc51954b0817fa8e6cMichal Marek#include <sys/utsname.h>
4153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
4296573a02208abebe4a884c0bbd0d6ecde9047f37Lucas De Marchi#include <shared/util.h>
4396573a02208abebe4a884c0bbd0d6ecde9047f37Lucas De Marchi
4453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi/* kmod_elf_get_section() is not exported, we need the private header */
451315123955f8c53e5ac9f7f5fb937c5e110aa4f1Lucas De Marchi#include <libkmod/libkmod-internal.h>
4653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
4753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi/* FIXME: hack, change name so we don't clash */
4853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#undef ERR
4953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include "testsuite.h"
5053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi#include "stripped-module.h"
5153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
5253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchistruct mod {
5353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	struct mod *next;
5453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	int ret;
5553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	int errcode;
5653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	char name[];
5753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi};
5853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
5953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchistatic struct mod *modules;
6053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchistatic bool need_init = true;
61a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchistatic struct kmod_ctx *ctx;
6253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
6353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchistatic void parse_retcodes(struct mod *_modules, const char *s)
6453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi{
6553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	const char *p;
6653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
6753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	if (s == NULL)
6853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		return;
6953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
7053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	for (p = s;;) {
7153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		struct mod *mod;
7253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		const char *modname;
7353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		char *end;
7453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		size_t modnamelen;
7553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		int ret, errcode;
7653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		long l;
7753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
7853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		modname = p;
7953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		if (modname == NULL || modname[0] == '\0')
8053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			break;
8153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
8253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		modnamelen = strcspn(s, ":");
8353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		if (modname[modnamelen] != ':')
8453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			break;
8553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
8653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		p = modname + modnamelen + 1;
8753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		if (p == NULL)
8853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			break;
8953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
9053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		l = strtol(p, &end, 0);
9153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		if (end == p || *end != ':')
9253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			break;
9353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		ret = (int) l;
9453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		p = end + 1;
9553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
9653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		l = strtol(p, &end, 0);
9753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		if (*end == ':')
9853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			p = end + 1;
9953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		else if (*end != '\0')
10053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			break;
10153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
10253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		errcode = (int) l;
10353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
10453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		mod = malloc(sizeof(*mod) + modnamelen + 1);
10553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		if (mod == NULL)
10653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			break;
10753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
10853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		memcpy(mod->name, modname, modnamelen);
10953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		mod->name[modnamelen] = '\0';
11053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		mod->ret = ret;
11153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		mod->errcode = errcode;
11253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		mod->next = _modules;
11353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		_modules = mod;
11453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	}
11553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi}
11653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
1175a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchistatic int write_one_line_file(const char *fn, const char *line, int len)
1185a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi{
1195a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        FILE *f;
1205a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        int r;
1215a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1225a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        assert(fn);
1235a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        assert(line);
1245a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1255a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        f = fopen(fn, "we");
1265a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        if (!f)
1275a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                return -errno;
1285a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1295a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        errno = 0;
1305a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        if (fputs(line, f) < 0) {
1315a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                r = -errno;
1325a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                goto finish;
1335a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        }
1345a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1355a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        fflush(f);
1365a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1375a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        if (ferror(f)) {
1385a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                if (errno != 0)
1395a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                        r = -errno;
1405a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                else
1415a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                        r = -EIO;
1425a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        } else
1435a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi                r = 0;
1445a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1455a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchifinish:
1465a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        fclose(f);
1475a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi        return r;
1485a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi}
1495a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1505a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchistatic int create_sysfs_files(const char *modname)
1515a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi{
1525a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	char buf[PATH_MAX];
1535a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	const char *sysfsmod = "/sys/module/";
1545a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	int len = strlen(sysfsmod);
1555a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1565a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	memcpy(buf, sysfsmod, len);
1575a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	strcpy(buf + len, modname);
1585a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	len += strlen(modname);
1595a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
160c493b937509596eb038a00926a714c3c99615287Lucas De Marchi	assert(mkdir_p(buf, len, 0755) >= 0);
1615a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
1625a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	strcpy(buf + len, "/initstate");
1635a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi	return write_one_line_file(buf, "live\n", strlen("live\n"));
1645a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi}
1655a2949cdf32cf6193992e3362c161ee1df978d2aLucas De Marchi
16653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchistatic struct mod *find_module(struct mod *_modules, const char *modname)
16753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi{
16853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	struct mod *mod;
16953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
17053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	for (mod = _modules; mod != NULL; mod = mod->next) {
1715c42c5fcedb3d1ce1de62711870e691cf768f4caLucas De Marchi		if (streq(mod->name, modname))
17253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi			return mod;
17353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	}
17453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
17553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	return NULL;
17653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi}
17753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
17853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchistatic void init_retcodes(void)
17953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi{
18053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	const char *s;
18153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
18253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	if (!need_init)
18353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		return;
18453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
18553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	need_init = false;
18653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	s = getenv(S_TC_INIT_MODULE_RETCODES);
18753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	if (s == NULL) {
18853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		fprintf(stderr, "TRAP init_module(): missing export %s?\n",
18953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi						S_TC_INIT_MODULE_RETCODES);
19053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	}
19153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
192a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	ctx = kmod_new(NULL, NULL);
193a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
19453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	parse_retcodes(modules, s);
19553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi}
19653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
197a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchistatic inline bool module_is_inkernel(const char *modname)
198a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi{
199a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	struct kmod_module *mod;
200a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	int state;
201a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	bool ret;
202a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
203a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	if (kmod_module_new_from_name(ctx, modname, &mod) < 0)
204a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi		return false;
205a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
206a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	state = kmod_module_get_initstate(mod);
207a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
208a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	if (state == KMOD_MODULE_LIVE ||
209a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi			state == KMOD_MODULE_BUILTIN)
210a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi		ret = true;
211a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	else
212a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi		ret = false;
213a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
214a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	kmod_module_unref(mod);
215a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
216a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	return ret;
217a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi}
218a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
219fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchistatic uint8_t elf_identify(void *mem)
220fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi{
221fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	uint8_t *p = mem;
222fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	return p[EI_CLASS];
223fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi}
224fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi
22553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De MarchiTS_EXPORT long init_module(void *mem, unsigned long len, const char *args);
22653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
22753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi/*
228ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi * Default behavior is to try to mimic init_module behavior inside the kernel.
229ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi * If it is a simple test that you know the error code, set the return code
230ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi * in TESTSUITE_INIT_MODULE_RETCODES env var instead.
231ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi *
232ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi * The exception is when the module name is not find in the memory passed.
233ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi * This is because we want to be able to pass dummy modules (and not real
234ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi * ones) and it still work.
23553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi */
23653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchilong init_module(void *mem, unsigned long len, const char *args)
23753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi{
23853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	const char *modname;
23953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	struct kmod_elf *elf;
24053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	struct mod *mod;
24153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	const void *buf;
24253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	uint64_t bufsize;
24353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	int err;
244fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	uint8_t class;
245fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	off_t offset;
24653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
24753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	init_retcodes();
24853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
24953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	elf = kmod_elf_new(mem, len);
25053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	if (elf == NULL)
25153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		return 0;
25253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
25353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	err = kmod_elf_get_section(elf, ".gnu.linkonce.this_module", &buf,
25453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi								&bufsize);
25553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	kmod_elf_unref(elf);
25653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
257fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	/* We couldn't parse the ELF file. Just exit as if it was successful */
25853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	if (err < 0)
25953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		return 0;
26053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
261fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	/* We need to open both 32 and 64 bits module - hack! */
262fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	class = elf_identify(mem);
263fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	if (class == ELFCLASS64)
264fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi		offset = MODULE_NAME_OFFSET_64;
265fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	else
266fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi		offset = MODULE_NAME_OFFSET_32;
267fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi
268fca5b9bcd4c57abb74eed3f766d5c58a7b827e71Lucas De Marchi	modname = (char *)buf + offset;
26953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	mod = find_module(modules, modname);
270ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi	if (mod != NULL) {
271ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi		errno = mod->errcode;
272ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi		err = mod->ret;
273a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	} else if (module_is_inkernel(modname)) {
274a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi		err = -1;
275a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi		errno = EEXIST;
276a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	} else
277ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi		err = 0;
27853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
279ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi	if (err == 0)
280ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi		create_sysfs_files(modname);
281ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi
282ddf1e7a61711580fee4d8d904a4a388aafecce27Lucas De Marchi	return err;
28353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi}
28453646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi
285063086e038657de64f9980bc51954b0817fa8e6cMichal Marekstatic int check_kernel_version(int major, int minor)
286063086e038657de64f9980bc51954b0817fa8e6cMichal Marek{
287063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	struct utsname u;
288063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	const char *p;
289063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	int maj = 0, min = 0;
290063086e038657de64f9980bc51954b0817fa8e6cMichal Marek
291063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	if (uname(&u) < 0)
292063086e038657de64f9980bc51954b0817fa8e6cMichal Marek		return false;
293063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	for (p = u.release; *p >= '0' && *p <= '9'; p++)
294063086e038657de64f9980bc51954b0817fa8e6cMichal Marek		maj = maj * 10 + *p - '0';
295063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	if (*p == '.')
296063086e038657de64f9980bc51954b0817fa8e6cMichal Marek		for (p++; *p >= '0' && *p <= '9'; p++)
297063086e038657de64f9980bc51954b0817fa8e6cMichal Marek			min = min * 10 + *p - '0';
298063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	if (maj > major || (maj == major && min >= minor))
299063086e038657de64f9980bc51954b0817fa8e6cMichal Marek		return true;
300063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	return false;
301063086e038657de64f9980bc51954b0817fa8e6cMichal Marek}
302063086e038657de64f9980bc51954b0817fa8e6cMichal Marek
303063086e038657de64f9980bc51954b0817fa8e6cMichal Marek
304e87352d289aa19ed388e9e19507d86a39936f3b4Kees CookTS_EXPORT int finit_module(const int fd, const char *args, const int flags);
305e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook
306e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cookint finit_module(const int fd, const char *args, const int flags)
307e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook{
308e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	int err;
309e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	void *mem;
310e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	unsigned long len;
311e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	struct stat st;
312e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook
313063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	if (!check_kernel_version(3, 8)) {
314063086e038657de64f9980bc51954b0817fa8e6cMichal Marek		errno = ENOSYS;
315063086e038657de64f9980bc51954b0817fa8e6cMichal Marek		return -1;
316063086e038657de64f9980bc51954b0817fa8e6cMichal Marek	}
317e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	if (fstat(fd, &st) < 0)
318e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook		return -1;
319e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook
320e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	len = st.st_size;
321e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	mem = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
322e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	if (mem == MAP_FAILED)
323e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook		return -1;
324e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook
325e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	err = init_module(mem, len, args);
326e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	munmap(mem, len);
327e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook
328e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook	return err;
329e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook}
330e87352d289aa19ed388e9e19507d86a39936f3b4Kees Cook
3310ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De MarchiTS_EXPORT long int syscall(long int __sysno, ...)
3320ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi{
3330ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	va_list ap;
3340ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	long ret;
3350ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi
3368e00db9537fee379d900b352b4f6750c52d17726Lucas De Marchi	if (__sysno == -1) {
3378e00db9537fee379d900b352b4f6750c52d17726Lucas De Marchi		errno = ENOSYS;
3380ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		return -1;
3398e00db9537fee379d900b352b4f6750c52d17726Lucas De Marchi	}
3408e00db9537fee379d900b352b4f6750c52d17726Lucas De Marchi
3418e00db9537fee379d900b352b4f6750c52d17726Lucas De Marchi	if (__sysno == __NR_finit_module) {
3420ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		const char *args;
3430ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		int flags;
3440ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		int fd;
3450ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi
3460ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		va_start(ap, __sysno);
3470ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi
3480ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		fd = va_arg(ap, int);
3490ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		args = va_arg(ap, const char *);
3500ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		flags = va_arg(ap, int);
3510ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi
3520ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		ret = finit_module(fd, args, flags);
3530ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi
3540ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		va_end(ap);
3550ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi		return ret;
3560ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	}
3570ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi
3580ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	/*
3590ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	 * FIXME: no way to call the libc function - let's hope there are no
3600ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	 * other users.
3610ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	 */
3620ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi	abort();
3630ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi}
3640ae58609dc0b983aa17ea7aa38c071cf1830819aLucas De Marchi
36553646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi/* the test is going away anyway, but lets keep valgrind happy */
36653646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchivoid free_resources(void) __attribute__((destructor));
36753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchivoid free_resources(void)
36853646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi{
36953646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	while (modules) {
37053646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		struct mod *mod = modules->next;
37153646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		free(modules);
37253646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi		modules = mod;
37353646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi	}
374a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi
375a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi	if (ctx)
376a655370541b5ddd681e864ddf23b1e3e214830b7Lucas De Marchi		kmod_unref(ctx);
37753646fc56f32b7e3e7a2a8cd1e24aeb6b3422dbcLucas De Marchi}
378