#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/utsname.h>
#include "config.h"
char *module_whitelist[] = {
"rtai_math", "rtai_sem", "rtai_fifos", "rtai_up", "rtai_lxrt",
"rtai_hal", "rtai_sched", "rtai_smi", "rtai", "rt_mem_mgr", "adeos",
NULL
};
char *path_whitelist[] = {
"/lib/modules", RTDIR, NULL,
NULL
};
char *ext_whitelist[] = {
".ko", NULL
};
void error(int argc, char **argv) {
int i;
int res;
char *prog = argv[0];
res = setuid(getuid());
if(res != 0)
{
perror("setuid");
exit(1);
}
fprintf(stderr, "%s: Invalid usage with args:", argv[0]);
for(i=1; i<argc; i++) {
fprintf(stderr, " %s", argv[i]);
}
fprintf(stderr, "\n\nUsage: %s insert /path/to/module.ext [param1=value1 ...]\n", prog);
fprintf(stderr, "\nwhere module is one of:\n");
for(i=0; module_whitelist[i]; i++) {
fprintf(stderr, "\t%s\n", module_whitelist[i]);
}
fprintf(stderr, "\nthe path starts with one of:\n");
for(i=0; path_whitelist[i]; i++) {
fprintf(stderr, "\t%s\n", path_whitelist[i]);
}
fprintf(stderr, "\nand the extension is one of:\n");
for(i=0; ext_whitelist[i]; i++) {
fprintf(stderr, "\t%s\n", ext_whitelist[i]);
}
fprintf(stderr, "\nor the module is in the directory %s\n",
EMC2_RTLIB_DIR);
fprintf(stderr, "\nOR\n\n%s remove module\n\nwhere module is one of"
" the modules listed above.\n\n", prog);
exit(1);
}
char *check_whitelist(char *target, char *table[]) {
int i;
if(!target) return 0;
for(i=0; table[i]; i++) {
int sz = strlen(table[i]);
if(!strncmp(target, table[i], sz)) return target + sz;
}
return 0;
}
void check_whitelist_module_path(char *mod, int argc, char **argv) {
char *ext, *end;
char *last_slash = strrchr(mod, '/');
if(!last_slash || strstr(mod, "..")) error(argc, argv);
if(strncmp(mod, EMC2_RTLIB_DIR, strlen(EMC2_RTLIB_DIR)) == 0)
return;
ext = check_whitelist(last_slash + 1, module_whitelist);
if(!ext) error(argc, argv);
end = check_whitelist(ext, ext_whitelist);
if(!end || *end) error(argc, argv);
if(!check_whitelist(mod, path_whitelist)) error(argc, argv);
}
#include <sys/types.h>
#include <dirent.h>
void check_whitelist_module(char *mod, int argc, char **argv) {
char *end;
DIR *d = opendir(EMC2_RTLIB_DIR);
if(d) {
char buf[NAME_MAX + 1];
snprintf(buf, NAME_MAX, "%s%s", mod, MODULE_EXT);
while(1) {
struct dirent *ent = readdir(d);
if(!ent) break;
if(strcmp(ent->d_name, buf) == 0) {
closedir(d);
return;
}
}
closedir(d);
}
end = check_whitelist(mod, module_whitelist);
if(!end || *end) error(argc, argv);
}
int main(int argc, char **argv) {
char *mod;
int i;
int inserting = 0;
int res;
struct utsname u;
char buf[4096];
char **exec_argv;
if(geteuid() != 0) {
fprintf(stderr, "module_helper is not setuid root\n");
return 1;
}
res = seteuid(getuid());
if(res != 0)
{
perror("seteuid");
return 1;
}
res = uname(&u);
if(res != 0)
{
perror("uname");
return 1;
}
res = snprintf(buf, sizeof(buf), "/usr/realtime-%s/modules", u.release);
if(res < 0 || res >= sizeof(buf))
{
perror("snprintf");
return 1;
}
path_whitelist[2] = buf;
if(argc < 3) error(argc, argv);
if(strcmp(argv[1], "insert") && strcmp(argv[1], "remove")) error(argc, argv);
exec_argv = malloc(argc * sizeof(char *));
if(!strcmp(argv[1], "insert"))
inserting = 1;
mod = argv[2];
if(inserting) {
check_whitelist_module_path(mod, argc, argv);
exec_argv[0] = "/sbin/insmod";
exec_argv[1] = mod;
for(i=3; i<argc; i++) {
exec_argv[i-1] = argv[i];
}
exec_argv[argc-1] = NULL;
} else {
check_whitelist_module(mod, argc, argv);
exec_argv[0] = "/sbin/rmmod";
exec_argv[1] = mod;
exec_argv[2] = NULL;
}
res = seteuid(0);
if(res != 0)
{
perror("seteuid");
return 1;
}
execve(exec_argv[0], exec_argv, NULL);
perror("execv failed");
return 1;
}