checkpoint-restore / criu

Checkpoint/Restore tool
criu.org
Other
2.97k stars 596 forks source link

how to fork a process with compel #2377

Open zhuizhuhaomeng opened 7 months ago

zhuizhuhaomeng commented 7 months ago

Description

I would like to fork a child in the tracee. But I got a segment fault.

Steps to reproduce the issue:

This is the parasite code:

#include <unistd.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/prctl.h>

#include <compel/infect-rpc.h>
#include <compel/plugins/std/syscall.h>
#include <compel/plugins/std/log.h>
#include <plugins/std/infect.h>

/*
 * Stubs for std compel plugin.
 */
int compel_main(void *arg_p, unsigned int arg_s)
{
    return 0;
}
int parasite_trap_cmd(int cmd, void *args)
{
    return 0;
}
void parasite_cleanup(void)
{
}

#define ptr_to_u64(ptr)    ((__u64)((uintptr_t)(ptr)))
#define PARASITE_CMD_CLONE PARASITE_USER_CMDS

int parasite_daemon_cmd(int cmd, void *args)
{
    struct timespec req = { .tv_sec = 1000, .tv_nsec = 0 };
    struct timespec rem = { .tv_sec = 0, .tv_nsec = 0 };

    if (cmd == PARASITE_CMD_CLONE) {
        int pidfd = -1;
        pid_t parent_tid = -1, pid = -1;
        struct clone_args args = {
            .stack = 0,
            .stack_size = 0,
            .parent_tid = ptr_to_u64(&parent_tid),
            .pidfd = ptr_to_u64(&pidfd),
            .flags = CLONE_CLEAR_SIGHAND,
            .exit_signal = 0, // SIGCHLD
        };

        pid = sys_clone3(&args, sizeof(args));
        if (pid < 0) {
            return -1;
        }

        if (pid == 0) {
            int i;
            for (i = 0; i < 10000; i++) {
                sys_nanosleep(&req, &rem);
            }
            sys_exit(0);

            return 0;
        }
    }

    return 0;
}

And this is the spy.c

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

#include <compel/log.h>
#include <compel/infect-rpc.h>
#include <compel/infect-util.h>

#include "parasite.h"

#define PARASITE_CMD_CLONE PARASITE_USER_CMDS

static void print_vmsg(unsigned int lvl, const char *fmt, va_list parms)
{
    printf("\tLC%u: ", lvl);
    vprintf(fmt, parms);
}

static int do_infection(int pid, int debug)
{
    //int child_pid;

#define err_and_ret(msg)              \
    do {                          \
        fprintf(stderr, msg); \
        return -1;            \
    } while (0)

    int state;
    struct parasite_ctl *ctl;
    struct infect_ctx *ictx;

    /* compel_log_init(print_vmsg, COMPEL_LOG_DEBUG); */
    if (debug) {
        compel_log_init(print_vmsg, COMPEL_LOG_DEBUG);
    } else {
        compel_log_init(print_vmsg, COMPEL_LOG_INFO);
    }

    printf("Stopping task\n");
    state = compel_stop_task(pid);
    if (state < 0)
        err_and_ret("Can't stop task");

    printf("Preparing parasite ctl\n");
    ctl = compel_prepare(pid);
    if (!ctl)
        err_and_ret("Can't prepare for infection");

    printf("Configuring contexts\n");

    /*
     * First -- the infection context. Most of the stuff
     * is already filled by compel_prepare(), just set the
     * log descriptor for parasite side, library cannot
     * live w/o it.
     */
    ictx = compel_infect_ctx(ctl);
    ictx->log_fd = STDERR_FILENO;

    parasite_setup_c_header(ctl);

    printf("Infecting\n");
    if (compel_infect(ctl, 1, sizeof(int)))
        err_and_ret("Can't infect victim");

    if (compel_rpc_call(PARASITE_CMD_CLONE, ctl))
        err_and_ret("Can't run cmd");

    if (compel_rpc_sync(PARASITE_CMD_CLONE, ctl))
        err_and_ret("Con't finalize cmd");

    /*
     * Done. Cure and resume the task.
     */
    printf("Curing\n");
    if (compel_cure(ctl))
        err_and_ret("Can't cure victim");

    if (compel_resume_task(pid, state, state))
        err_and_ret("Can't unseize task");

    printf("Done\n");
    return 0;
}

int main(int argc, char **argv)
{
    int pid;
    int debug = 0;

    if (argc < 2) {
        fprintf(stderr, "%s PID DEBUG\n", argv[0]);
        return 1;
    }

    pid = atoi(argv[1]);

    if (argc >= 3) {
        debug = atoi(argv[2]);
    }

    /*
     * Now do the infection with parasite.c
     */

    printf("Infecting the tracee %d\n", pid);
    if (do_infection(pid, debug))
        return 1;

    return 0;
}

Describe the results you received:

[47871.778937] nginx[152231]: segfault at cccccccd ip 00000000cccccccd sp 00007ffff78c69a0 error 14 in libpcre2-8.so.0.10.2[7ffff5b51000+3000] likely on CPU 0 (core 0, socket 0)

github-actions[bot] commented 6 months ago

A friendly reminder that this issue had no activity for 30 days.