I write C application that calls fork() to create child processes. The application runs as root. In the parent process, I use wait() for waiting terminated child processes. In child processes, I use prctl() with PR_SET_PDEATHSIG option to detect the death of the parent. It works fine. To reduce the risk of security issues, child processes call setuid() to change UID. The problem is: child processes can not detect the death of the parent one any more.
I have searched around to find the answer and found some useful links, but it does not help:
Detect death of parent process
Enforcing process hierarchies (prctl related) : although this link contains a clear answer, there is no solution.
How to do that correctly?
I just stumbled upon the same issue, the kernel resets the PDEATH signal on credential change:
https://github.com/torvalds/linux/blob/master/kernel/cred.c#L450
This can be verified with the following code and strace -f:
#include <sys/prctl.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char *argv[])
{
if (fork() == 0) {
// This works as expected
setgid(1000);
setuid(1000);
prctl(PR_SET_PDEATHSIG, SIGTERM);
// This doesn't work since pdeath_signal will be reset
// setgid(1000);
// setuid(1000);
pause();
}
sleep(1);
kill(getpid(), SIGTERM);
return (0);
}
Related
I have a C program that uses fork-execv to create a child process to run a Python program. I want the parent and child processes to communicate through IPC (for example, FIFOs) and the child process will continue running for the duration of the parent process, performing Python functions for the parent at intervals signalled through IPC.
My problem is that once the child process starts it prevents the C program from running, so there is no opportunity for the two to interact. The C program is created on the main thread, not with a new thread created with pthreads.
It looks like the solution is to use clone() instead of fork(), which is also helpful because I want the two programs to share the same heap, which I can't do with fork().
The Python child process runs in a while True loop to keep it running while the parent process proceeds. Here is a very simplified version for the purpose of illustration (without IPC):
#!/usr/bin/python3
import os
import time
a = 0
while True:
a = a + 1
if a > 50000:
a = 0
time.sleep(1)
The C program for fork-execv:
#include <sys/types.h> /* for pid_t */
#include <sys/wait.h> /* for wait */
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
int call_PyFn(int64_t fdx)
{
//Create buffer for file descriptor
int buflen = (int)((ceil(log10(fdx))+1)*sizeof(char));
char fdbuf[buflen];
sprintf(fdbuf, "%d", (int)fdx);
int status;
char * paramsList[] = {
"/usr/bin/python3",
"-m",
"NLTK_Python_Libs",
"-c",
fdbuf,
(char *)NULL };
if ( fork() == 0 ){
printf("I am the child\n");
execv(paramsList[0],paramsList); }
else {
printf("I am the parent\n");
wait( &status ); }
return 0;
}
My questions are:
Will clone() run the child process on a separate thread?
When I do multithreading work I use pthread_setaffinity to pin each thread to a specific core. Can I do that with clone()? From the docs, "If CLONE_THREAD is set, the child is placed in the same thread group as the calling process" but "without specifying CLONE_THREAD, then the resulting thread is placed in a new thread group whose TGID is the same as the thread's TID." https://linux.die.net/man/2/clone. That doesn't completely answer this question re affinity. Ideally I would like the two processes to run on the same core so that if I use this in a multicore project I can have each core run its own cloned process on the second thread of the parent's core.
I've read a lot of information on this but nothing completely clears it up for me. In the scenario described, am I right that fork does not create a new thread, which results in the child process blocking the parent, whereas clone will create a new thread?
It looks like the answer is yes, but confirmation would help. The question at How to create a real thread with clone() on Linux? comes close, but doesn't clear up all my questions.
Thanks.
Is there any way to prevent creation of zombie processes while I am using fork() and exec() to run an application in background? The parent should not wait() for the child to complete. Also I cannot use sigaction() and sigaction.sa_handler because it affects all child processes which I don't want. I want something that will reap that particular child only, or that will prevent from spawning any zombie. Please help.
If you want to create a "detached" process that you don't have to wait for, the best way is to fork twice so that it's a "grandchild" process. Immediately waitpid on the direct child process, which should call _exit immediately after forking again (so this waitpid does not block forward progress in the parent). The grandchild process will be orphaned so it gets inherited by the init process and you never have to deal with it again.
Alternatively you can install a signal handler for SIGCHLD with SA_NOCLDWAIT. However this is a really bad idea in general since its effects are global. It will badly break any library code you use that needs to be able to wait for child processes, including standard library functions like popen, possibly wordexp, possibly grantpt, etc.
To prevent of zombie processes you need to tell the parent to wait for the child, until the child's terminates the process.
You need to use the waitpid() function that is included in the library 'sys/wait.h'
Down here you have an example code that you can use the waitpid() function.
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main()
{
pid_t child_pid;
int status;
int local = 0;
/* now create new process */
child_pid = fork();
if (child_pid >= 0) /* fork succeeded */
{
if (child_pid == 0) /* fork() returns 0 for the child process */
{
printf("child process!\n");
// Increment the local and global variables
printf("child PID = %d, parent pid = %d\n", getpid(), getppid());
}
else /* parent process */
{
printf("parent process!\n");
printf("parent PID = %d, child pid = %d\n", getpid(), child_pid);
wait(&status); /* wait for child to exit, and store child's exit status */
}
//code ..
#R: In fairness, there ARE usercases where one might fork a job, and where there is absolutely no need to react on the result of the spawned child.
Any call of a wait() function may eventually block the parent if there is no answer, may it? This might crash an airplane...
You can register a signal handler mechanism to prevent the child process to get zombie,
this
Link will be helpful to resolution of your problem.
I've created a rudimentary example of monitoring a child process and restarting it when it fails or exits. What is the preferred/more robust method of doing this? Is it good practice to continuously poll for a change in status? My understanding is that I should utilize something like SIGCHLDbut have been unable to find any good examples.
I'm an embedded C coder mainly and this is my first attempt at trying to understand fork().The purpose of this code will eventually be to monitor a call to another program using exec() and restart this program if and when it fails or finishes.
Edit:
After comments from #cnicutar I have rewritten the example below in a way I think makes more sense in the hope that it is of use to somebody later. I would like the parent to monitor a child process whilst foing other things and make a new call to exec on a new fork when the child process fails/finishes. I want to try and use unix signals to achieve this
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
pid_t cpid;
int status;
cpid = fork();
for (;;)
{
switch (cpid)
{
case -1 : //Fork failure
exit(EXIT_FAILURE);
break;
case 0 : //Child Process
exec(some function);
return 0; //exit child process
break;
default : //Parent process
if (waitpid(-1, &status, WNOHANG) != 1) cpid = fork(); //restart
//Do parent stuff here...
break;
}
}
}
Adding a SIGCHLD handler won't buy you much since you already wait all the time and only do that - there's nothing else to "interrupt".
One thing I would suggest is a threshold such that the process doesn't die/start too often.
My understanding is that I should utilize something like SIGCHLD but
have been unable to find any good examples
You use SIGCHLD to know when to wait. A typical SIGCHLD handler just does waitpid in a loop until no children are left. In your case you don't need that since your main code is a loop stopped on waitpid.
EDIT
You can find plenty of examples for SIGCHLD handling. One such example is How can I handle sigchld in C. In that code, after the while you can just fork:
while((pid = waitpid(-1, &status, WNOHANG)) > 0)
;
pid = fork();
switch (pid)
...
To reiterate, if you do this SIGCHLD will be called every time a child dies and after you properly wait for it you can just fork another. This only makes sense if the parent has better stuff to do in the meantime than to just block on waitpid.
Word to the wise. There are certain functions that must not be called from a signal handler lest you add difficult bugs to your program. Look up "async signal safe" functions: these and only these can be called from a signal handler. Some of the most common functions (like printf and malloc) cannot be called from a signal handler.
/* In alarm.c, the first function, ding, simulates an alarm clock. */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static int alarm_fired = 0;
void ding(int sig)
{
alarm_fired = 1;
}
/* In main, we tell the child process to wait for five seconds
before sending a SIGALRM signal to its parent. */
int main()
{
pid_t pid;
printf("alarm application starting\n");
pid = fork();
switch(pid) {
case -1:
/* Failure */
perror("fork failed");
exit(1);
case 0:
/* child */
sleep(5);
printf("getppid: %d\n", getppid());
kill(getppid(), SIGALRM);
exit(0);
}
/* The parent process arranges to catch SIGALRM with a call to signal
and then waits for the inevitable. */
printf("waiting for alarm to go off\n");
(void) signal(SIGALRM, ding);
printf("pid: %d\n", getpid());
pause();
if (alarm_fired)
printf("Ding!\n");
printf("done\n");
exit(0);
}
I have run the above code under Ubuntu 10.04 LTS
> user#ubuntu:~/Documents/./alarm
> alarm application starting
> waiting for alarm to go off
> pid: 3055
> getppid: 3055
> Ding!
> done
I have read the following statement from a book.
It’s important to be clear about the
difference between the fork system
call and the creation of new threads.
When a process executes a fork call, a
new copy of the process is created
with its own variables and its own
PID. This new process is scheduled
independently, and (in general)
executes almost independently of the
process that created it.
Question:
It seems to me that the variable alarm_fired is shared between the original process and the new created process.
Is that correct?
No. Each process gets its own copy of the variable (and pretty much everything else). If you change the variable in one process, it is changed only in that process, not in both. Each process has its own address space.
Compare that with threads, where all threads share a single address space, so a change in a variable in one thread will be visible in all other threads (within that process).
From the Linux fork(2) manpage:
fork() creates a child process that differs from the parent process only in its PID and PPID, and in the fact that resource utilizations are set to 0. File locks and pending signals are not inherited.
It is shared in the sense that immediately after the fork it has the same value in both processes. BUT when either writes to it the change is not propagated to the other process (that what different .
Also, see copy on write for interesting stuff.
EDIT
It seems that the new created process
modified the variable alarm_fired
which is then later seen by the old
process
The child is sending a signal to the parent. The parent then executes the handler and personally sets alarm_fired to one. The child itself never touches that variable.
No, variables are not shared across a fork(). In your code, the child process never touches alarm_fired. What the child does is send a signal to the parent. That signal fires a signal handler in the parent process' context, setting the variable.
I am sorry I am repeating a question https://stackoverflow.com/questions/5687837/monitor-implementation-in-c but not getting a solution as yet. I have probably asked the question incorrectly.
Say I have a code portion B. A parent process spawns a number of child processes to execute code B but I would like only one process to be inside code portion B at a time. How can I do it in C on Linux platform?
Thanks for your help
An edit. Not threads but process.
You want a mutex.
pthread_mutex_t mutexsum;
pthread_mutex_init(&mutexsum, NULL);
pthread_mutex_lock (&mutexsum);
// Critical code
pthread_mutex_unlock (&mutexsum);
If you are serious about it being multiple processes instead of multiple threads, the mutex needs to be stored in a shared memory segment.
So what you want is to have exactly one child running at any point of time, then why spawn all the children processes all at once?
When a child process ends, a SIGCHLD is issued, you can write your own handler for this signal and call spawn from the handler. Then you have one new child process created when one perishes -- only one child process running. Below is a hack (useless, just for demo) to achieve this:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
void spawn(void){
pid_t child_pid=fork();
if(child_pid > 0){
printf("new child created by %d !\n",getpid());
sleep(1);
}else if(child_pid == 0){
printf("child %d created !\n",getpid());
}else{
exit(EXIT_FAILURE);
}
}
void handler(int sigval){
spawn();
}
int main(void){
signal(SIGCHLD,handler);
spawn();
return 0;
}