[LINUX] [C language] How to create, avoid, and make a zombie process

【Overview】

We will make zombies using the T-virus developed by the pharmaceutical company Umbrella. That's a joke, and I'll show you how to create, avoid, and make Buddhahood processes in C.

[Easy zombie process]

A zombie process is a child process in which the parent process leaves the child process alone and cannot be terminated indefinitely.

【environment】

[vagrant@vagrant-centos65 ~]$ cat /etc/redhat-release 
CentOS release 6.5 (Final)

[How to create a zombie]

First, the source for creating zombies

zombie.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int
main(int argc, char *argv[])
{
    pid_t pid;

    //Argument check
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
        exit(1);
    }

    //fork to create a child process
    //In the process after fork, two processes, a parent process and a child process, are executed at the same time.
    pid = fork();
    if (pid < 0) {
        fprintf(stderr, "fork(2) failed\n");
        exit(1);
    }

    //The return value of the fork of the child process is 0
    if (pid == 0) { /*What the child process does*/
        execl(argv[1], argv[1], argv[2], NULL);
        /* execl()Will not return if successful, so everything will fail if returned*/
        perror(argv[1]);
        exit(99);
    }
    //The return value of the fork of the parent process is the process ID of the child process
    else {          /*What the parent process does*/
        //Zombie survival time is 30 seconds
        //I set it to 30 seconds here, but while(1)In the case of an infinite loop such as, zombies will always exist
        sleep(30);
        printf("child (PID=%d) finished;\n", pid);
        exit(0);
    }
}

Be careful how to make zombies

Argument 1: Full path of the command to be executed (this time / bin / echo) Argument 2: Parameter for the command of argument 1 (this time This is zombie)

If you execute as below, the prompt will not return for 30 seconds, and you will not be able to confirm the existence of zombies on the same terminal. (If you want to check the zombies by raising another terminal, you can use the following method.)

[vagrant@vagrant-centos65 tmp]$ gcc -o zombie ./zombie.c 
[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie"
This is zombie //→ In this state, you have to wait for 30 seconds, you cannot do other work, etc.
child (PID=24579) finished; //→ Displayed after 30 seconds
[vagrant@vagrant-centos65 tmp]$ 

Therefore, add & at the end of the command as shown below and execute it in the background process. We also confirm that zombies exist with the ps command during the 30 seconds that zombies exist. You can confirm that it is a zombie because defunct is displayed in the result of the ps command.

[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 24601
[vagrant@vagrant-centos65 tmp]$ This is zombie
//→ If you do not press enter, the prompt will not be returned, so press enter
[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
vagrant  24602  0.0  0.0      0     0 pts/0    Z    23:06   0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ child (PID=24602) finished; //→ Displayed after 30 seconds
//→ If you do not press enter, the prompt will not be returned, so press enter
[1]+  Done                    ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$ 

[How to avoid zombies]

Method ① After fork (), waitpid ()

After forking, the parent process uses waitpid to catch the termination of the child process. It is the parent's responsibility to prevent zombies from occurring.

zombie_avoid1.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int
main(int argc, char *argv[])
{
    pid_t pid;

    //Argument check
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
        exit(1);
    }

    //fork to create a child process
    //In the process after fork, two processes, a parent process and a child process, are executed at the same time.
    pid = fork();
    if (pid < 0) {
        fprintf(stderr, "fork(2) failed\n");
        exit(1);
    }

    //The return value of the fork of the child process is 0
    if (pid == 0) { /*What the child process does*/
        execl(argv[1], argv[1], argv[2], NULL);
        /* execl()Will not return if successful, so everything will fail if returned*/
        perror(argv[1]);
        exit(99);
    }
    //The return value of the fork of the parent process is the process ID of the child process
    else {          /*What the parent process does*/
        int status;

        waitpid(pid, &status, 0);
        sleep(30);
        printf("child (PID=%d) finished; ", pid);
        if (WIFEXITED(status))
            printf("exit, status=%d\n", WEXITSTATUS(status));
        else if (WIFSIGNALED(status))
            printf("signal, sig=%d\n", WTERMSIG(status));
        else
            printf("abnormal exit\n");
        exit(0);
    }
}
【Execution result】

You can confirm that the zombie does not exist with the ps command.

[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid1 ./zombie_avoid1.c 
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid1 /bin/echo "This is zombie" &
[1] 24619
[vagrant@vagrant-centos65 tmp]$ This is zombie

[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ child (PID=24620) finished; exit, status=0

[1]+  Done                    ./zombie_avoid1 /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$ 

Method ② Double fork

Create a child process from a parent process and a grandchild process from a child process. And by terminating the child process, the grandchild process does not become a zombie because the parent process from the grandchild process no longer exists. Make sure that the grandchild process still exists when the parent and child processes terminate.

process processの終了時間
Parent process Finish after 30 seconds
Child process Immediate end
Grandchild process Finish after 60 seconds

zombie_avoid2.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int
main(int argc, char *argv[])
{
    pid_t pid;

    //Argument check
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
        exit(1);
    }

    //fork to create a child process
    //In the process after fork, two processes, a parent process and a child process, are executed at the same time.
    pid = fork();
    if (pid < 0) {
        fprintf(stderr, "fork(2) failed\n");
        exit(1);
    }

    //The return value of the fork of the child process is 0
    if (pid == 0) { /*What the child process does*/
        pid_t pid_child;
        pid_child = fork();
        if (pid_child < 0) {
            fprintf(stderr, "child fork(2) failed\n");
            exit(1);
        }

        if (pid_child == 0) { /*What the grandchild process does*/
            execl(argv[1], argv[1], argv[2], NULL);
            /* execl()Will not return if successful, so everything will fail if returned*/
            perror(argv[1]);
            exit(99);
        } else { /*What the child process does*/
            printf("grandchild (PID=%d) finished; ", pid_child);
            exit(0);
        }
    }
    //The return value of the fork of the parent process is the process ID of the child process
    else {          /*What the parent process does*/
        int status;

        waitpid(pid, &status, 0);
        sleep(30);
        printf("child (PID=%d) finished; ", pid);
        if (WIFEXITED(status))
            printf("exit, status=%d\n", WEXITSTATUS(status));
        else if (WIFSIGNALED(status))
            printf("signal, sig=%d\n", WTERMSIG(status));
        else
            printf("abnormal exit\n");
        exit(0);
    }
}
【Execution result】

This time I'm using sleep instead of ʻecho` to check for the existence of grandchild processes.

[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid2 ./zombie_avoid2.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid2 /bin/sleep 60 &
[1] 25674
[vagrant@vagrant-centos65 tmp]$ grandchild (PID=25676) finished; 
[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ 
//Zombies do not exist
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
//Grandchild process exists
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
vagrant  25676  0.0  0.1 100924   620 pts/0    S    01:29   0:00 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$ child (PID=25675) finished; exit, status=0

[1]+  Done                    ./zombie_avoid2 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$ 
//The grandchild process still exists when the parent process terminates
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
vagrant  25676  0.0  0.1 100924   620 pts/0    S    01:29   0:00 /bin/sleep 60
[vagrant@vagrant-centos65 tmp]$
//The grandchild process also ends after 60 seconds
[vagrant@vagrant-centos65 tmp]$ ps aux | grep 25676 | grep -v grep
[vagrant@vagrant-centos65 tmp]$ 

Method ③ Use sigaction

zombie_avoid3.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>

static void detach_children(void);
static void noop_handler(int sig);

int
main(int argc, char *argv[])
{
    pid_t pid;

    //Argument check
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <command> <arg>\n", argv[0]);
        exit(1);
    }

    detach_children();

    //fork to create a child process
    //In the process after fork, two processes, a parent process and a child process, are executed at the same time.
    pid = fork();
    if (pid < 0) {
        fprintf(stderr, "fork(2) failed\n");
        exit(1);
    }

    //The return value of the fork of the child process is 0
    if (pid == 0) { /*What the child process does*/
        execl(argv[1], argv[1], argv[2], NULL);
        /* execl()Will not return if successful, so everything will fail if returned*/
        perror(argv[1]);
        exit(99);
    }
    //The return value of the fork of the parent process is the process ID of the child process
    else {          /*What the parent process does*/
    	printf("child (PID=%d) finished;\n", pid);
    	//Since the signal is caught in sleep, it loops infinitely in while
    	while(1);
        exit(0);
    }
}

static void
detach_children(void)
{
    struct sigaction act;

    act.sa_handler = noop_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_RESTART | SA_NOCLDWAIT;
    if (sigaction(SIGCHLD, &act, NULL) < 0) {
        printf("sigaction() failed: %s", strerror(errno));
    }
}

static void
noop_handler(int sig)
{
    ;
}
【Execution result】
[vagrant@vagrant-centos65 tmp]$ gcc -o zombie_avoid3 ./zombie_avoid3.c
[vagrant@vagrant-centos65 tmp]$ ./zombie_avoid3 /bin/echo "This is zombie" &
[1] 25895
[vagrant@vagrant-centos65 tmp]$ child (PID=25896) finished;
This is zombie

[vagrant@vagrant-centos65 tmp]$ 
//Zombies do not exist
[vagrant@vagrant-centos65 tmp]$ ps aux | grep defunct | grep -v grep
// zombie_avoid3 process exists
[vagrant@vagrant-centos65 tmp]$ ps aux | grep zombie_avoid3 | grep -v grep
vagrant  25895  102  0.0   3924   448 pts/0    R    02:42   0:13 ./zombie_avoid3 /bin/echo This is zombie
[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ kill 25895
[vagrant@vagrant-centos65 tmp]$ 
[1]+  Terminated              ./zombie_avoid3 /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$ 

[Zombie Buddhahood Method]

I will show you how to terminate the zombie process created in zombie.c.

Zombies cannot be defeated by attacking the zombies themselves (child processes).

[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 25932
[vagrant@vagrant-centos65 tmp]$ This is zombie

[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant  25932  0.0  0.0   3920   372 pts/0    S    02:47   0:00 ./zombie /bin/echo This is zombie
vagrant  25933  0.0  0.0      0     0 pts/0    Z    02:47   0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$ 
//Kill zombies
[vagrant@vagrant-centos65 tmp]$ kill 25933
//Killed a zombie, but the zombie exists
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant  25932  0.0  0.0   3920   372 pts/0    S    02:47   0:00 ./zombie /bin/echo This is zombie
vagrant  25933  0.0  0.0      0     0 pts/0    Z    02:47   0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ child (PID=25933) finished;

[1]+  Done                    ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$ 

A zombie can be defeated by attacking the zombie's head (parent process).

[vagrant@vagrant-centos65 tmp]$ ./zombie /bin/echo "This is zombie" &
[1] 25965
[vagrant@vagrant-centos65 tmp]$ This is zombie

[vagrant@vagrant-centos65 tmp]$ 
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
vagrant  25965  0.0  0.0   3920   372 pts/0    S    02:50   0:00 ./zombie /bin/echo This is zombie
vagrant  25966  0.0  0.0      0     0 pts/0    Z    02:50   0:00 [echo] <defunct>
[vagrant@vagrant-centos65 tmp]$ 
//Kill the parent process
[vagrant@vagrant-centos65 tmp]$ kill 25965
[vagrant@vagrant-centos65 tmp]$ 
[1]+  Terminated              ./zombie /bin/echo "This is zombie"
[vagrant@vagrant-centos65 tmp]$
//There are no parent processes or zombies
[vagrant@vagrant-centos65 tmp]$ ps aux | grep -e zombie -e defunct | grep -v grep
[vagrant@vagrant-centos65 tmp]$ 

【Reference book】

[Normal Linux programming 2nd edition: The royal road of gcc programming that can be learned from the mechanism of Linux](https://www.amazon.co.jp/%E3%81%B5%E3%81%A4%E3%81%86% E3% 81% AELinux% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0-% E7 % AC% AC2% E7% 89% 88-Linux% E3% 81% AE% E4% BB% 95% E7% B5% 84% E3% 81% BF% E3% 81% 8B% E3% 82% 89% E5 % AD% A6% E3% 81% B9% E3% 82% 8Bgcc% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83 % B3% E3% 82% B0% E3% 81% AE% E7% 8E% 8B% E9% 81% 93-% E9% 9D% 92% E6% 9C% A8-% E5% B3% B0% E9% 83 % 8E-ebook / dp / B075ST51Y5)

[Reference site]

How to create a zombie process double fork to avoid zombie process

Recommended Posts

[C language] How to create, avoid, and make a zombie process
Try to make a Python module in C language
How to create and use static / dynamic libraries in C
How to make a Japanese-English translation
How to make a slack bot
How to create a Conda package
How to make a crawler --Advanced
How to make a recursive function
How to create a virtual bridge
How to make a deadman's switch
How to create a Dockerfile (basic)
[Blender] How to make a Blender plugin
How to make a crawler --Basic
How to create a config file
[C language] [Linux] Try to create a simple Linux command * Just add! !!
Overview of how to create a server socket and how to establish a client socket
I tried to make a periodical process with Selenium and Python
How to create a clone from Github
How to split and save a DataFrame
How to create a git clone folder
[Python] How to make a class iterable
How to create a repository from media
How to make a Backtrader custom indicator
How to make a Pelican site map
How to divide and process a data frame using the groupby function
How to make a process thread run only on a specific CPU core
How to make a container name a subdomain and make it accessible in Docker
How to make a request to bitFlyer Lightning's Private API in Go language
3. Natural language processing with Python 1-2. How to create a corpus: Aozora Bunko
How to make a dialogue system dedicated to beginners
How to create a Python virtual environment (venv)
How to create explanatory variables and objective functions
How to create a JSON file in Python
How to make a dictionary with a hierarchical structure.
How to multi-process exclusive control in C language
Make a chatbot and practice to be popular.
How to make a QGIS plugin (package generation)
How to create a shortcut command for LINUX
I read "How to make a hacking lab"
[Note] How to create a Ruby development environment
How to create a Kivy 1-line input box
How to create a multi-platform app with kivy
How to create a Rest Api in Django
[Note] How to create a Mac development environment
I tried to make a periodical process with CentOS7, Selenium, Python and Chrome
How to read a serial number file in a loop, process it, and graph it
C language to see and remember Part 3 Call C language from Python (argument) c = a + b
[Python] How to create a local web server environment with SimpleHTTPServer and CGIHTTPServer
Read the Python-Markdown source: How to create a parser
How to display the modification date of a file in C language up to nanoseconds
How to create a submenu with the [Blender] plugin
[GCF + Python] How to upload Excel to GCS and create a new table in BigQuery
How to make a shooting game with toio (Part 1)
[Go] How to create a custom error for Sentry
How to create a USB that Linux and Win10 installer and winpe can boot UEFI
How to create a Python 3.6.0 environment by putting pyenv on Amazon Linux and Ubuntu
How to make a Python package using VS Code
How to create a local repository for Linux OS
[Python] How to create Correlation Matrix and Heat Map
Basics of PyTorch (2) -How to make a neural network-
How to create a simple TCP server / client script