Created
March 31, 2026 13:40
-
-
Save bjackman/131069a6de9adb66df7ca8e12ea2a196 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define _GNU_SOURCE | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <sys/types.h> | |
| #include <sys/uio.h> | |
| #include <unistd.h> | |
| #include <sys/wait.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <sys/mman.h> | |
| #include <stdbool.h> | |
| #include <sched.h> | |
| #include <sys/syscall.h> | |
| #define STACK_SIZE (1024 * 1024) | |
| #ifndef SYS_memfd_secret | |
| #define SYS_memfd_secret 447 | |
| #endif | |
| struct child_args { | |
| int write_pipe_fd; | |
| bool use_memfd; | |
| bool use_memfd_secret; | |
| }; | |
| static int child_func(void *arg) { | |
| struct child_args *args = (struct child_args *)arg; | |
| int pipe_fd = args->write_pipe_fd; | |
| bool use_memfd = args->use_memfd; | |
| bool use_memfd_secret = args->use_memfd_secret; | |
| const char *message = "Hello from the child's memory!"; | |
| size_t msg_len = strlen(message) + 1; | |
| void *msg_ptr; | |
| char stack_message[64]; // Declare it here so it's in scope for the whole child life | |
| if (use_memfd_secret) { | |
| int fd = syscall(SYS_memfd_secret, 0); | |
| if (fd == -1) { | |
| perror("[Child] memfd_secret"); | |
| if (errno == ENOSYS) { | |
| fprintf(stderr, "[Child] memfd_secret not supported by kernel.\n"); | |
| } else if (errno == ENOTTY) { | |
| fprintf(stderr, "[Child] memfd_secret not enabled in kernel (secretmem_enable=1 boot param?).\n"); | |
| } | |
| return EXIT_FAILURE; | |
| } | |
| if (ftruncate(fd, msg_len) == -1) { | |
| perror("[Child] ftruncate"); | |
| return EXIT_FAILURE; | |
| } | |
| msg_ptr = mmap(NULL, msg_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | |
| if (msg_ptr == MAP_FAILED) { | |
| perror("[Child] mmap"); | |
| return EXIT_FAILURE; | |
| } | |
| memcpy(msg_ptr, message, msg_len); | |
| printf("[Child] Using memfd_secret-backed memory at address: %p\n", msg_ptr); | |
| close(fd); | |
| } else if (use_memfd) { | |
| int fd = memfd_create("demo_memfd", 0); | |
| if (fd == -1) { | |
| perror("[Child] memfd_create"); | |
| return EXIT_FAILURE; | |
| } | |
| if (ftruncate(fd, msg_len) == -1) { | |
| perror("[Child] ftruncate"); | |
| return EXIT_FAILURE; | |
| } | |
| msg_ptr = mmap(NULL, msg_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | |
| if (msg_ptr == MAP_FAILED) { | |
| perror("[Child] mmap"); | |
| return EXIT_FAILURE; | |
| } | |
| memcpy(msg_ptr, message, msg_len); | |
| printf("[Child] Using memfd-backed memory at address: %p\n", msg_ptr); | |
| close(fd); | |
| } else { | |
| strcpy(stack_message, message); | |
| msg_ptr = stack_message; | |
| printf("[Child] Using stack-allocated memory at address: %p\n", msg_ptr); | |
| } | |
| printf("[Child] My PID is %d\n", getpid()); | |
| printf("[Child] Message content: %s\n", message); | |
| // Send the address of the message to the parent | |
| if (write(pipe_fd, &msg_ptr, sizeof(void *)) == -1) { | |
| perror("[Child] write"); | |
| return EXIT_FAILURE; | |
| } | |
| // Keep the child alive long enough for the parent to read its memory | |
| sleep(2); | |
| printf("[Child] Exiting...\n"); | |
| close(pipe_fd); | |
| return EXIT_SUCCESS; | |
| } | |
| int main(int argc, char *argv[]) { | |
| bool use_memfd = false; | |
| bool use_memfd_secret = false; | |
| for (int i = 1; i < argc; i++) { | |
| if (strcmp(argv[i], "--memfd") == 0) { | |
| use_memfd = true; | |
| } else if (strcmp(argv[i], "--memfd_secret") == 0) { | |
| use_memfd_secret = true; | |
| } | |
| } | |
| int pipefd[2]; | |
| if (pipe(pipefd) == -1) { | |
| perror("pipe"); | |
| exit(EXIT_FAILURE); | |
| } | |
| // Allocate stack for the cloned child process | |
| char *stack = malloc(STACK_SIZE); | |
| if (!stack) { | |
| perror("malloc"); | |
| exit(EXIT_FAILURE); | |
| } | |
| // clone() requires the top of the stack | |
| char *stackTop = stack + STACK_SIZE; | |
| struct child_args cargs; | |
| cargs.write_pipe_fd = pipefd[1]; | |
| cargs.use_memfd = use_memfd; | |
| cargs.use_memfd_secret = use_memfd_secret; | |
| pid_t pid = clone(child_func, stackTop, SIGCHLD, &cargs); | |
| if (pid == -1) { | |
| perror("clone"); | |
| free(stack); | |
| exit(EXIT_FAILURE); | |
| } | |
| // Parent process | |
| close(pipefd[1]); // Close unused write end | |
| void *remote_address; | |
| char local_buffer[64]; | |
| memset(local_buffer, 0, sizeof(local_buffer)); | |
| // Read the address from the child | |
| ssize_t read_bytes = read(pipefd[0], &remote_address, sizeof(void *)); | |
| if (read_bytes <= 0) { | |
| if (read_bytes == 0) { | |
| fprintf(stderr, "[Parent] Pipe closed by child (child probably failed).\n"); | |
| } else { | |
| perror("[Parent] read from pipe"); | |
| } | |
| wait(NULL); | |
| free(stack); | |
| exit(EXIT_FAILURE); | |
| } | |
| printf("[Parent] Child PID: %d\n", pid); | |
| printf("[Parent] Remote address to read: %p\n", remote_address); | |
| struct iovec local[1]; | |
| local[0].iov_base = local_buffer; | |
| local[0].iov_len = sizeof(local_buffer) - 1; | |
| struct iovec remote[1]; | |
| remote[0].iov_base = remote_address; | |
| remote[0].iov_len = sizeof(local_buffer) - 1; | |
| // Use process_vm_readv to read from the child's address space | |
| ssize_t nread = process_vm_readv(pid, local, 1, remote, 1, 0); | |
| if (nread == -1) { | |
| perror("[Parent] process_vm_readv"); | |
| wait(NULL); | |
| free(stack); | |
| exit(EXIT_FAILURE); | |
| } | |
| printf("[Parent] Successfully read %zd bytes from child\n", nread); | |
| printf("[Parent] Data read: \"%s\"\n", local_buffer); | |
| close(pipefd[0]); | |
| wait(NULL); // Wait for child to finish | |
| printf("[Parent] Child has exited. Parent exiting.\n"); | |
| free(stack); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment