Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share memory with only one of multiple child processes?

I'm working on an application in C on Linux which manages multiple sandboxed environments, each in its own kernel namespaces. These environments are eventually intended to be as isolated as possible, both from the rest of the system and from eachother, but the ability to communicate with them via, among other things, shared memory regions, is still needed. I've currently got this working by mmaping shared memory with MAP_SHARED and MAP_ANONYMOUS, but of course this grants all child processes access to all of my application's shared memory. There does not appear to be a trivial/"built-in" way to specify that a memory region is to be shared with one child process (i.e. not PRIVATE) but not with all child processes (i.e. not SHARED) either.

#define _GNU_SOURCE
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/mman.h>

//Stack size for the containers
#define STACK_SIZE (1024 * 1024)

int *share;

//Two child processes that just read and print the shared state
int child1(void* arg){
    for(int i=0;i<6;i++){
        printf("Child 1 reads state as: %d.\n", *share);
        sleep(1);
    }
    return 1;
}

int child2(void* arg){
    for(int i=0;i<6;i++){
        printf("Child 2 reads state as: %d.\n", *share);
        sleep(1);
    }
    return 1;
}

int main(){
    static char *stack_top;

    //Map shared memory for the shared value - how do I share this with only one child process?
    share = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    *share = 0;

    //Map memory for a stack for each child namespace and start them
    stack_top = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
    pid_t pid1 = clone(child1, stack_top + STACK_SIZE, CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWCGROUP | SIGCHLD, NULL);
    stack_top = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
    pid_t pid2 = clone(child2, stack_top + STACK_SIZE, CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWCGROUP | SIGCHLD, NULL);

    //Wait, then change the state
    sleep(3);
    *share = 1;
    printf("Changing state\n");

    //Wait for both processes to return
    waitpid(pid1, NULL, 0);
    waitpid(pid2, NULL, 0);

    return 0;
}

This is what I have at the moment. Obviously, both children can read the value in the shared memory.

Child 1 reads state as: 0.
Child 2 reads state as: 0.
Child 1 reads state as: 0.
Child 2 reads state as: 0.
Child 1 reads state as: 0.
Child 2 reads state as: 0.
Child 1 reads state as: 0.
Changing state
Child 2 reads state as: 1.
Child 1 reads state as: 1.
Child 2 reads state as: 1.
Child 1 reads state as: 1.
Child 2 reads state as: 1.

What's the best way to restrict shared memory access to only one of these? I can imagine maybe doing it with one trusted child process per sandbox, but that seems hacky and rather overcomplicated - surely there's a better way to do this?

like image 216
DodoDude700 Avatar asked Jan 31 '26 05:01

DodoDude700


1 Answers

I assume that the parent process wants to talk to all children but each child only should “see” the parent.

You need one mmap handle per child. First, create as many handles as you wish to have children. Then, for each child, clone, close all handles but the one for the child the fork is for (this unmaps the off-limits memory from the child process), then either stay in the process and run child code, or exec the child binary, preserving the open handles.

like image 94
Kuba hasn't forgotten Monica Avatar answered Feb 01 '26 19:02

Kuba hasn't forgotten Monica



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!