Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ebpf): correct value of exit and signal code for sched_process_exit #4564

Merged
merged 1 commit into from
Jan 30, 2025

Conversation

rscampos
Copy link
Collaborator

@rscampos rscampos commented Jan 29, 2025

1. Explain what the PR does

a13d497 fix: get exit code and signal values

When a process exits normally via exit(n), the exit code is
stored in the upper byte (exit_code << 8). The lower byte is
used for signal information if the process was terminated by
a signal.

Also, align the type of exit_code used at struct task_struct.

2. Explain how to test it

Use the following code to trigger:

gcc -o trigger trigger.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

int main() {
    printf("Forking process...\n");
    pid_t pid = fork();
    
    if (pid == 0) {
        printf("Child process running, PID: %d\n", getpid());
        sleep(10);
        printf("Child process exiting normally\n");
        exit(1);
    } else if (pid > 0) {
        // Parent process
        sleep(1);
        printf("Parent sending SIGKILL to child PID: %d\n", pid);
        kill(pid, SIGKILL);
        wait(NULL);
    } else {
        perror("fork");
        return 1;
    }

    exit(77);
}

Tracee before this PR:

sudo ./dist/tracee -e sched_process_exit -s comm=trigger
TIME             UID    COMM             PID     TID     RET              EVENT                     ARGS
12:08:14:542122  1000   trigger          3133042 3133042 0                sched_process_exit        exit_code: 9, process_group_exit: true
12:08:14:542306  1000   trigger          3133041 3133041 0                sched_process_exit        exit_code: 19712, process_group_exit: true

Tracee after this PR:

sudo ./dist/tracee -e sched_process_exit -s comm=trigger
TIME             UID    COMM             PID     TID     RET              EVENT                     ARGS
12:09:52:080566  1000   trigger          3137039 3137039 0                sched_process_exit        exit_code: 1, signal_code: 9, process_group_exit: true
12:09:52:081407  1000   trigger          3137038 3137038 0                sched_process_exit        exit_code: 77, signal_code: 0, process_group_exit: true

3. Other comments

fix #4566

@rscampos rscampos changed the title fix(ebpf): get exit code value fix(ebpf): get the correct value of exit code Jan 29, 2025
Copy link
Member

@geyslan geyslan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

As exit_code might contain a signal value, it would be great to extract that also, so a new arg "signal" should be added in the case of PF_SIGNALED is set.

@rscampos rscampos force-pushed the fix_exit_code_value branch 2 times, most recently from ea18817 to f6d22e2 Compare January 29, 2025 18:03
@rscampos rscampos marked this pull request as ready for review January 29, 2025 18:04
@rscampos rscampos force-pushed the fix_exit_code_value branch 2 times, most recently from 2163ca3 to b0a256a Compare January 29, 2025 19:14
@rscampos rscampos changed the title fix(ebpf): get the correct value of exit code fix(ebpf): correct value of exit and signal code for sched_process_exit Jan 29, 2025
@rscampos rscampos force-pushed the fix_exit_code_value branch 2 times, most recently from 7bd8240 to d533a5f Compare January 29, 2025 22:30
When a process exits normally via exit(n), the exit code is
stored in the upper byte (exit_code << 8). The lower byte is
used for signal information if the process was terminated by
a signal.

Also, align the type of exit_code used at struct task_struct.
@geyslan
Copy link
Member

geyslan commented Jan 30, 2025

@OriGlassman FYI.

Copy link
Member

@geyslan geyslan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

I've tested with this trigger:

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

// Signal handler for SIGUSR1
void handle_sigusr1(int sig) {
    printf("Child process %d received SIGUSR1\n", getpid());
}

int main() {
    printf("Forking processes...\n");

    // Create first child process
    pid_t pid1 = fork();
    if (pid1 == 0) {
        printf("Child process 1 running, PID: %d\n", getpid());
        sleep(10);
        printf("Child process 1 exiting normally\n");
        exit(1);  // Exit with code 1
    } else if (pid1 < 0) {
        perror("fork");
        return 1;
    }

    // Create second child process
    pid_t pid2 = fork();
    if (pid2 == 0) {
        printf("Child process 2 running, PID: %d\n", getpid());
        sleep(10);
        printf("Child process 2 exiting normally\n");
        exit(2);  // Exit with code 2
    } else if (pid2 < 0) {
        perror("fork");
        return 1;
    }

    // Create third child process (to be signaled and terminated, since it doesn't handle SIGUSR1)
    pid_t pid3 = fork();
    if (pid3 == 0) {
        printf("Child process 3 running, PID: %d\n", getpid());
        while (1) {
            sleep(1);  // Keep running until signaled
        }
    } else if (pid3 < 0) {
        perror("fork");
        return 1;
    }

    // Create fourth child process (to be signaled and handled)
    pid_t pid4 = fork();
    if (pid4 == 0) {
        // Install signal handler for SIGUSR1
        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = handle_sigusr1;
        sigaction(SIGUSR2, &sa, NULL);

        printf("Child process 4 running, PID: %d\n", getpid());
        sleep(10);
        printf("Child process 4 killing itself\n");
        kill(getpid(), SIGKILL);
    } else if (pid4 < 0) {
        perror("fork");
        return 1;
    }

        // Create fourth child process (to be signaled and handled)
    pid_t pid5 = fork();
    if (pid5 == 0) {
        // Install signal handler for SIGUSR2
        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = handle_sigusr1;
        sigaction(SIGUSR2, &sa, NULL);

        printf("Child process 5 running, PID: %d\n", getpid());
        sleep(10);
        printf("Child process 5 exiting normally\n");
        exit(5);  // Exit with code 5
    } else if (pid4 < 0) {
        perror("fork");
        return 1;
    }

    // Parent process
    sleep(1);

    // Send SIGUSR1 to child processes 3 and 4
    printf("Parent sending SIGUSR1 to child PID: %d\n", pid3);
    kill(pid3, SIGUSR1);
    printf("Parent sending SIGUSR2 to child PID: %d\n", pid4);
    kill(pid4, SIGUSR2);
    printf("Parent sending SIGUSR2 to child PID: %d\n", pid5);
    kill(pid5, SIGUSR2);

    // Wait for all child processes to finish
    int status;
    waitpid(pid1, &status, 0);
    if (WIFEXITED(status)) {
        printf("Child process 1 exited with status: %d\n", WEXITSTATUS(status));
    }

    waitpid(pid2, &status, 0);
    if (WIFEXITED(status)) {
        printf("Child process 2 exited with status: %d\n", WEXITSTATUS(status));
    }

    waitpid(pid3, &status, 0);
    if (WIFSIGNALED(status)) {
        printf("Child process 3 was terminated by signal: %d\n", WTERMSIG(status));
    }

    waitpid(pid4, &status, 0);
    if (WIFSIGNALED(status)) {
        printf("Child process 4 was terminated by signal: %d\n", WTERMSIG(status));
    }

    waitpid(pid5, &status, 0);
    if (WIFEXITED(status)) {
        printf("Child process 5 exited with status: %d\n", WEXITSTATUS(status));
    }

    printf("Parent process exiting\n");
    exit(77);
}

And got the following output:

11:46:04:850047  1000   exiter           1405739 1405739 0                sched_process_exit        exit_code: 0, signal_code: 10, process_group_exit: true
11:46:04:850112  1000   exiter           1405740 1405740 0                sched_process_exit        exit_code: 0, signal_code: 9, process_group_exit: true
11:46:04:850122  1000   exiter           1405741 1405741 0                sched_process_exit        exit_code: 5, signal_code: 0, process_group_exit: true
11:46:13:849992  1000   exiter           1405737 1405737 0                sched_process_exit        exit_code: 1, signal_code: 0, process_group_exit: true
11:46:13:850050  1000   exiter           1405738 1405738 0                sched_process_exit        exit_code: 2, signal_code: 0, process_group_exit: true
11:46:13:850373  1000   exiter           1405736 1405736 0                sched_process_exit        exit_code: 77, signal_code: 0, process_group_exit: true

@rscampos
Copy link
Collaborator Author

Thank you @geyslan for the test :)

@rscampos
Copy link
Collaborator Author

/fast-forward

@github-actions github-actions bot merged commit a13d497 into aquasecurity:main Jan 30, 2025
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incorrectly reports exit code in sched_process_exit event
2 participants