Reputation: 45
I am using Ubuntu with VirtualBox. I am defining a new command to my shell to output some characteristics(like sibling tree etc.) of child processes. In order to output these characteristics, I created a kernel module and used task_struct. I also tested my kernel module outside of my shell and it works. Now my problem is how to trigger this kernel module inside my shell(in C code) so that my kernel module will be loaded?
I searched and find that I need to use system calls like modprobe or insmod but did not understand how to use them. I tried the code below, but it did not work:
setuid(0);
system("/sbin/insmod /.../mymodule.ko");
Thank you for your help.
Upvotes: 3
Views: 3374
Reputation: 14763
system()
You are trying to become root in your application (by executing setuid(0)
), but you don't have permissions to do that (if you run your program as regular user). Instead, you should check if your program was run from root (using getuid()
). Also, it's good idea to test if your module file exists at all. Here is an example of such code (it's tested and does all checking needed):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define ROOT_UID 0
#define INSMOD_PATH "/sbin/insmod"
#define MOD_PATH "/.../mymodule.ko"
int main(void)
{
uid_t uid;
int res;
/* Check if program being run by root */
uid = getuid();
if (uid != ROOT_UID) {
fprintf(stderr, "Error: Please run this program as root\n");
return EXIT_FAILURE;
}
/* Check if module file exists */
if (access(MOD_PATH, F_OK) == -1) {
fprintf(stderr, "Error: File \"%s\" doesn't exist\n", MOD_PATH);
return EXIT_FAILURE;
}
/* Load module */
res = system(INSMOD_PATH " " MOD_PATH);
if (res != 0) {
fprintf(stderr, "Error loading module: %d\n", res);
return EXIT_FAILURE;
}
printf("Module \"%s\" was successfully loaded\n", MOD_PATH);
return EXIT_SUCCESS;
}
Save this code as main.c
file. Be sure to replace MOD_PATH definition with actual path of your module file.
Compile it using next command:
$ gcc -Wall -O2 main.c -o load_module
Now do the next:
$ su
# ./load_module
sudo -s
command instead of su
.Pay your attention to the last character at the command prompt:
#
means you have root permissions at this point$
means you only have regular user permissions.finit_module()
Using system()
function in C is usually considered a bad practice (because it takes a lot of time for execution and basically just trying to replace a much more simple Bash script).
If you want to load kernel module in C without using system()
, you can look into source code of insmod
tool. See libkmod/libkmod-module.c
file, kmod_module_insert_module()
function. You can see those sources here.
Pay attention to finit_module()
function call. A good explanation about this system call can be found at manual pages:
$ man finit_module
Here is an example how you can use finit_module()
system call:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ROOT_UID 0
#define MOD_PATH "/.../mymodule.ko"
static inline int finit_module(int fd, const char *uargs, int flags)
{
return syscall(__NR_finit_module, fd, uargs, flags);
}
int main(void)
{
uid_t uid;
long res;
int fd;
/* Check if program being run by root */
uid = getuid();
if (uid != ROOT_UID) {
fprintf(stderr, "Error: Please run this program as root\n");
return EXIT_FAILURE;
}
/* Check if module file exists */
if (access(MOD_PATH, F_OK) == -1) {
fprintf(stderr, "Error: File \"%s\" doesn't exist\n", MOD_PATH);
return EXIT_FAILURE;
}
/* Load module */
fd = open(MOD_PATH, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
perror("Unable to open module file");
return EXIT_FAILURE;
}
res = finit_module(fd, "", 0);
if (res != 0) {
perror("Error when loading module");
close(fd);
return EXIT_FAILURE;
}
close(fd);
printf("Module \"%s\" was successfully loaded\n", MOD_PATH);
return EXIT_SUCCESS;
}
Upvotes: 9