Why do I get a seg fault on Ubuntu but not mac? - c

I have a program that checks the modification time of a file and executes the file if it has changed. Currently it works if I run it on my mac, but it seg faults if I run it on ubuntu. Please help me.
note: this is in c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CONTERROR(cond, statement) \
if (cond) { \
perror(statement); \
continue; \
}
#define FATALERROR(cond, statement) \
if (cond) { \
perror(statement); \
exit(EXIT_FAILURE); \
}
/**
* Handler for the signals.
*/
static void handler(int signum) {
;
}
/**
* Main.
*/
int main(int argc, char *argv[]) {
struct sigaction sa;
struct stat buf;
struct itimerval tb;
pid_t pid;
int modTime;
if (argc != 2) {
fprintf(stderr, "usage: remote file\n");
exit(EXIT_FAILURE);
}
FATALERROR(stat(argv[1], &buf) == -1, "stat");
modTime = buf.st_mtime;
tb.it_interval.tv_sec = 0;
tb.it_interval.tv_usec = 50000;
tb.it_value.tv_sec = 0;
tb.it_value.tv_usec = 50000;
setitimer(ITIMER_REAL, &tb, 0);
sa.sa_handler = handler;
FATALERROR(sigemptyset(&sa.sa_mask) == -1, "mask");
FATALERROR(sigaction(SIGALRM, &sa, NULL) == -1, "sigaction");
while (1) {
pause();
CONTERROR(stat(argv[1], &buf) == -1, "stat");
if (modTime != buf.st_mtime) {
modTime = buf.st_mtime;
pid = fork();
FATALERROR(pid == -1, "fork");
if (!pid) {
execlp("rexec", "rexec", NULL);
fprintf(stderr, "exec\n");
}
}
}
exit(EXIT_SUCCESS);
}

Most of your sigaction structure is not initialized, so could contain random data. If sa_flags.SA_SIGINFO is accidentally set in this uninitialized data, then the signal will cause sa_sigaction instead of sa_handler to be called, which is also uninitialized, so will almost certainly crash.
You may find it easier to debug if you initialize all the fields, including making sure you have set the flags in a way the ensures the signals behaves the way you want.

Related

Why clone function return -1 when specifing CLONE_THREAD flag?

I write a simple program to demonstrate the thread creation, but the clone function return -1 and I don't know what's wrong with my program. Thanks.
The perror says Invalid argument.
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
static int child_func(void *arg)
{
sleep(3600);
return 0;
}
int main(int argc, char **argv)
{
// Allocate stack for child task.
const int STACK_SIZE = 65536;
char *stack = malloc(STACK_SIZE);
int status;
if (!stack) {
perror("malloc");
exit(1);
}
if (clone(child_func, stack + STACK_SIZE, CLONE_THREAD, NULL) == -1) {
perror("clone");
exit(1);
}
if (wait(&status) == -1) {
perror("wait");
exit(1);
}
sleep(3600);
printf("Child exited with status %d. buf = \"%s\"\n", status);
return 0;
}
You said you saw Invalid argument, which means EINVAL. From man 2 clone:
EINVAL CLONE_THREAD was specified in the flags mask, but CLONE_SIGHAND was not. (Since Linux 2.5.35.)
And that's exactly what you're doing.

Linux syscalls: PTRACE_O_TRACECLONE causes indefinite hanging

I have a binary from which I need to intercept a certain syscall--in this case unlinkat--and make it do nothing. I have the following code which works fine for a single process; however, with PTRACE_O_TRACECLONE added to the ptrace opts, after the tracee makes a call to clone, the waitpid call hangs forever. I've been pulling my hair out for days on different parts of the internet, to the point where I was going through the source of strace, and had in fact straced strace to see what the strace I had straced was ptracing.
Here's the source--I removed some stuff to make it as minimal as possible for readability.
#define _POSIX_C_SOURCE 200112L
// std (i think)
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// linux
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#define OPTS PTRACE_O_TRACESYSGOOD // | PTRACE_O_TRACECLONE | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEFORK
#define WOPTS 0
/* The TRACEE. Executes the process we want to target with PTRACE_TRACEME */
int do_child(int argc, char **argv) {
char *args[argc + 1];
memcpy(args, argv, argc * sizeof(char *));
args[argc] = NULL;
ptrace(PTRACE_TRACEME);
kill(getpid(), SIGSTOP);
return execvp(args[0], args);
}
/* Waits for the next syscall and checks to see if the process has been exited */
int wait_for_syscall(pid_t child) {
int status;
while (1) {
ptrace(PTRACE_SYSCALL, child, 0, 0);
waitpid(child, &status, WOPTS); // <--- THIS CALL HANGS FOREVER AFTER CLONE
if (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80)
return 0;
if (WIFEXITED(status))
return 1;
}
return -1; // unreachable
}
/* The TRACER. Takes the pid of the child process that we just started and actually does the
PTRACE stuff by passing signals back and forth to that process. */
int do_trace(pid_t child) {
int status, syscall;
waitpid(child, &status, WOPTS);
ptrace(PTRACE_SETOPTIONS, child, 0, (unsigned long)OPTS);
while (1) {
// ptrace(PTRACE_SYSCALL) really needs to be called twice, first is before entry second is after exit, but idgaf
if (wait_for_syscall(child) != 0) {
break;
}
syscall = ptrace(PTRACE_PEEKUSER, child, sizeof(long) * ORIG_RAX);
switch (syscall) {
case SYS_clone:
fprintf(stderr, "DEBUG: clone detected\n");
break;
case SYS_unlinkat:
fprintf(stderr, "DEBUG: unlinkat detected\n");
ptrace(PTRACE_POKEUSER, child, sizeof(long) * RAX, 0);
break;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s prog args\n", argv[0]);
exit(1);
}
pid_t child = fork();
if (child == 0) {
return do_child(argc - 1, argv + 1);
} else {
return do_trace(child);
}
return 0;
}
Just as a disclaimer, I am NOT a C developer, these days I mainly write Python, so a lot of this was just copied and pasted from different tutorials I found and I basically added/removed random shit until gcc didn't give me that many warnings.
Based on what I've read, I suspect the issue is something about raising signals to the processes involved and waiting for a SIGTRAP, I just have no real intuition on what to do at that level.
The solution was using libseccomp instead.
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <seccomp.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
int do_child(int argc, char **argv)
{
char *args[argc + 1];
memcpy(args, argv, argc * sizeof(char *));
args[argc] = NULL;
return execvp(args[0], args);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s prog args\n", argv[0]);
exit(1);
}
// Init the filter
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW); // default allow
// setup basic whitelist
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(0), SCMP_SYS(unlinkat), 0);
// build and load the filter
seccomp_load(ctx);
pid_t child = fork();
if (child == 0)
{
return do_child(argc - 1, argv + 1);
}
return 0;
}

Read Only shared memory segmentation fault [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm struggling with shared mem on linux paltform.
Cosider the following code:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#define SEM_NAME "mysem"
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
sleep(1);
}
return 0;
}
If I launch the app for a read only shared memory I get, as expected, segmentation fault the first time *ptr is incremented inside main loop.
I'm working on a lib that abstract Linux shared memory.
This lib will be deployed to third part developers that will implement some processes for my application on an embedded target.
This lib will implement "global variables" between processes. I was wondering if I can avoid to develop get and set function and simply return address of allocated memory.
In case of wrong permission access I want to give to caller infos about what was wrong in its code. Read segmentation fault on terminal and process termination does not give user a good information.
EDIT2
After #Ctx answer I tried the following solution but it works the first segmentation fault. The second trigger standard segmentation fault and pogram terminate.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
longjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = setjmp(env);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}
Per the mmap() man page:
Use of a mapped region can result in these signals:
SIGSEGV
Attempted write into a region mapped as read-only.
If you want to proceed if the modification doesn't work, you can install a signal handler for SIGSEGV and use (sig)setjmp/longjmp to continue execution at a defined point:
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
void somefunc(void) {
char *ptr = NULL;
signal(SIGSEGV, segvhandler);
if (!sigsetjmp(env, 1)) {
// Direct invocation, try the memory access
*ptr++;
}
signal(SIGSEGV, SIG_DFL);
}
int main (void) {
while (1) {
somefunc();
printf("One more iteration...\n");
}
exit(EXIT_SUCCESS); // Never reached
}
sigsetjmp(env, 1) also saves the blocked signals in env, when it's second argument is non-zero and siglongjmp() then restores these. Otherwise, the signal will still be blocked after longjmp(), since it is not a real return from the signal handler.
Keep in mind that you should only have the handler installed directly before you make the memory access in question and deinstall it afterwards.
a few minutes with the debugger shows the program crashes on the call to sem_wait().
if, after the call to sem_open() insert:
if( SEM_FAILED == mutex )
{
perror( "sem_open failed" );
exit( EXIT_FAILURE );
}
then move the statement:
sem_unlink(SEM_NAME);
to before the statement:
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
then it will become obvious that the remaining problem is in this statement:
printf("PID %d Count: %d\n", PID, (*ptr)++);
which causes a bus error signal to be raised. this bus error signal occurs on the very first pass through the while() loop.
there is a simple cause.
the printf() statement, last parameter is trying to both read and write the memory mapped file, but the memory mapping was only for (depending on the command line parameter) either 'PROT_READ' which allows reading or 'PROT_WRITE' which allows writing. the parameter to the call to mmap() needs to include both capabilities AND the call to open() also needs to
have the mode: O_RDWR. (the open() and the mmap() modes need to match
This is the corrected code after Ctx answer. I also found out THIS that is useful to understan why longjmp is not the right solution with signals.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = sigsetjmp(env, 1);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}

waitpid() not waiting for child

I wrote a really basic shell and for some reason, when I use fork() and then waitpid() the parent process won't wait for the child.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/limits.h>
#include "LineParser.h"
#include <termios.h>
#define MAX_STR 2048
void execute(cmdLine *pCmdLine);
int main()
{
char isContinuing = 1;
char path[PATH_MAX];
char str[MAX_STR];
char something[MAX_STR+PATH_MAX];
cmdLine* cmd;
while(isContinuing)
{
getcwd(path, PATH_MAX);
printf("%s$ ", path);
fgets(str, MAX_STR, stdin);
if(!strncmp(str, "quit", strlen("quit")))
{
isContinuing = 0;
}
else
{
cmd = parseCmdLines(str);
if(cmd->arguments != '\0')
{
execute(cmd);
}
}
}
freeCmdLines(cmd);
return 0;
}
void execute(cmdLine *pCmdLine)
{
pid_t id = fork();
if(id == 0)
{
printf("I AM CHILD.\n");
if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
{
perror("execvp failed.\n");
exit(1);
}
exit(0);
}
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id);
printf("DONE WAITING\n");
}
LineParser header file is mine and it is fully working.
Now, for some reason, only the first command is working as expected,
let's assume an input "echo hi", the output is:
I AM PARENT.
WAITING FOR CHILD.
I AM CHILD.
DONE WAITING.
as expected and then it prints "hi" and the path, waiting for a command again.
For some reason, when I enter the SAME input "echo hi" the second time, the output is:
I AM PARENT.
WAITING FOR CHILD.
DONE WAITING.
$PATH$ //(WITHOUT WAITING FOR INPUT !!!)
I AM CHILD.
hi
//and here waiting for input//
Why does this happen?
There are several problems with your code:
not clearing malloc'd memory on every iteration through the while loop
putting a exit() statement in unreachable code
incorrect parameter list for the waitpid() function
unclear delination between parent code and child code in execute function
unused variable something
failed to check return value from fgets function
missing #include for sys/types.h
missing #include for sys/wait.h
IMO: the question should have included the definition of struct cmdLine
So here is a compilable version of your code. The compiler found many problems with the original code.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/limits.h>
//#include "LineParser.h"
#include <termios.h>
#include <sys/types.h>
#include <sys/wait.h> // prototype for waitpid()
//note: pid_t waitpid(pid_t pid, int *status, int options);
struct cmdLine
{
char ** arguments; // arguments[x] = ptr to an argument string
};
#define MAX_STR (2048)
#define MAX_PATH (256)
void execute(struct cmdLine *);
struct cmdLine * parseCmdLines( char * );
void freeCmdLines( struct cmdLine * );
int main()
{
char path[PATH_MAX];
char str[MAX_STR];
//char something[MAX_STR+PATH_MAX];
struct cmdLine* pCmd = NULL;
while(1)
{
getcwd(path, PATH_MAX);
printf("%s$ ", path);
if( NULL == fgets(str, MAX_STR, stdin) )
{
perror( "fgets failed" );
exit( EXIT_FAILURE );
}
// implied else
if(!strncmp(str, "quit", strlen("quit")))
{ // then strings equal
break; // exit while loop (and pgm)
}
// implied else input not equal 'quit'
pCmd = parseCmdLines(str);
if( (NULL != pCmd) && (NULL != pCmd->arguments) )
{ // then one or more arguments entered/parsed
execute(pCmd);
} // end if
freeCmdLines(pCmd); // free all strings memory, then free struct memory
pCmd = NULL; // cleanup
} // end while
return 0;
} // end function: main
void execute(struct cmdLine *pCmdLine)
{
int status = 0;
pid_t id = fork();
if(id == 0)
{ // then, child
printf("I AM CHILD.\n");
if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
{ // if no error then never gets here
perror("execvp failed.\n");
} // end if
}
else
{ // else, parent
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id, &status, 0);
printf("DONE WAITING\n");
} // end if
} // end function: execute
You invoke undefined behavior by calling the waitpid() function with the wrong number of arguments. Anything could happen.
This simplified variant of your code works fine for me:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main ()
{
int i;
for (i = 0; i < 3; i += 1)
{
pid_t id = fork();
if(id == 0)
{
char *argv[] = { "echo", "hi", NULL };
printf("I AM CHILD.\n");
execvp("echo", argv);
/* failed to exec */
perror("execvp failed.\n");
exit(1);
} else if (id < 0) {
perror("fork failed.\n");
exit(1);
}
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id, NULL, 0);
printf("DONE WAITING\n");
}
return 0;
}
Your call to waitpid(2) is wrong.
According to man 2 waitpid, it's:
pid_t waitpid(pid_t pid, int *status, int options);
You probably need to define an int and call it as:
waitpid(id, &status, 0);
or use the simpler version wait(2), which will work for any child:
wait(&status);
Your main problem is that you don’t let the compiler check your code. You should generally enable the compiler warnings and try to understand them.
$ gcc -Wall -Wextra -Werror -Os -c myshell.c
This is the minimum command line I use. When your code compiles with these settings, you have already eliminated a bunch of hard-to-find bugs in your code. Among these bugs is, as others already have mentioned, the call to waitpid.
Have a look at http://pubs.opengroup.org/onlinepubs/7908799/xsh/waitpid.html. The Open Group specification requires that you #include the two headers <sys/types.h> and <sys/wait.h> before using the waitpid function. Your program doesn’t do this.

any example of copy_from_user() ? kernel and userspace

I am looking for copying PID value from User space to Kernel space, here is my code snaps.
Kernel Module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
MODULE_LICENSE ("GPL");
struct siginfo sinfo;
pid_t pid;
struct task_struct *task;
int init_module()
{
memset(&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGIO;
sinfo.si_code = SI_USER;
pid = 5218; // Everytime a new PID
// task = find_task_by_vpid(pid); I am also working on new and old version of UBUNTU so thats why this is here
task = pid_task(find_vpid(pid), PIDTYPE_PID);
printk("%d .\n", task);
if(task == NULL) {
printk("Cannot find PID from user program\r\n");
return 0;
}
send_sig_info(SIGIO, &sinfo, task);
return 0;
}
void cleanup_module ()
{
printk(KERN_ALERT"\nGoodBye World\n\n");
}
Userspace Code:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
void signal_handler(int signum)
{
if (signum == SIGIO) printf("SIGIO\r\n"); return;
}
int main()
{
int i = 1;
signal(SIGIO, signal_handler);
printf("My PID is %d.\n", getpid());
while (i);
return 0;
}
Now, here I am always running user space program to get PID and then I always have to edit the pid variable in Kernel module.
I found one way to access information from user space into Kernel space and vice-versa (i.e., using copy_from/to_user() )
But I am unable to understand either of them for getting a PID from user space, I have to make file in /dev directory and should apply all the required functions for just getting PID?
Is there any other way? if not, then can anyone please help me to do this? I am new in c programming and playing with kernel module directly so its hard for me.
Look into code you have given, it seems that you want to handle SIGIO signal
Here is my attempt to solve your problem,
signal_kernel.c file :
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
#include <linux/debugfs.h>
#include <linux/pid.h>
#define MAX 10
MODULE_LICENSE("GPL");
struct dentry *file;
static ssize_t write_conf_pid(struct file *file, const char *buf,
size_t count, loff_t *position)
{
char temp_str[MAX];
int ret;
int pid = 0;
struct siginfo sinfo;
struct task_struct *task;
/* NEVER TRUST USER INPUT */
if (count > MAX)
return -EINVAL;
if (copy_from_user(temp_str, buf, MAX) != 0)
return -EFAULT;
ret = sscanf(temp_str, "%d", &pid);
if (ret != 1) {
pr_info("Error in reading PID value from user");
return -EINVAL;
}
pr_info("User entered pid %d\n", pid);
memset(&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGIO;
sinfo.si_code = SI_USER;
task = pid_task(find_vpid(pid), PIDTYPE_PID);
if (task == NULL) {
pr_info("Cannot find PID from user program\r\n");
return -ENODEV;
}
ret = send_sig_info(SIGIO, &sinfo, task);
if (ret < 0)
pr_info("Error sending signal\n");
return count;
}
static const struct file_operations my_fops = {
.write = write_conf_pid,
};
int init_module()
{
/* Only root can write to this file */
file = debugfs_create_file("pidconf", 0200, NULL, NULL, &my_fops);
return 0;
}
void cleanup_module()
{
pr_info("\nGoodBye World\n\n");
}
signal_user.c file :
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
void signal_handler(int signum)
{
if (signum == SIGIO)
printf("SIGIO\r\n");
return;
}
int main()
{
int i = 1;
signal(SIGIO, signal_handler);
printf("My PID is %d.\n", getpid());
while (i);
return 0;
}
After compiling and running both user space and kernel space program, use debugfs interface to send PID value to Kernel space,
$ insmod signal_kernel.ko
$ ./signal_user
My PID is 17633.
... # Process will run in loop due to while(1)
From another terminal, provide PID to debugfs interface,
$ echo 17633 > /sys/kernel/debug/pidconf
There are various ways (sysfs, misc_char_device, char device etc.) to this task, but this will give you brief idea about using copy_from_user() and copy_to_user()
Please note that there is little error handling done in signal_user.c and signal_kernel.c.

Resources