summaryrefslogtreecommitdiff
path: root/internal/namespace/launcher_src/launcher.c
blob: e108da6995834a6e5d93c7224872f20adfa51791 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <grp.h>

int main(int argc, char **argv) {
    if (argc < 1) {
        fprintf(stderr, "Usage: %s <command> [args...]\n", argv[0]);
        return 1;
    }

    // 1. Capture host identities BEFORE unsharing
    uid_t current_uid = getuid();
    gid_t current_gid = getgid();

    // 2. Combined Unshare for User, Mount, and Network namespaces
    // We unshare Mount namespace (CLONE_NEWNS) to allow private /etc/resolv.conf setup
    // without contaminating the host filesystem.
    if (unshare(CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWNET) == -1) {
        perror("unshare(CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWNET)");
        return 1;
    }

    char map[64];

    // 3. Write UID map
    snprintf(map, sizeof(map), "0 %u 1\n", current_uid);
    int fd = open("/proc/self/uid_map", O_WRONLY);
    if (fd == -1) {
        perror("open uid_map");
        return 1;
    }
    if (write(fd, map, strlen(map)) == -1) {
        perror("write uid_map");
        close(fd);
        return 1;
    }
    close(fd);

    // 4. Disable setgroups
    fd = open("/proc/self/setgroups", O_WRONLY);
    if (fd != -1) {
        write(fd, "deny", 4);
        close(fd);
    }

    // 5. Write GID map
    snprintf(map, sizeof(map), "0 %u 1\n", current_gid);
    fd = open("/proc/self/gid_map", O_WRONLY);
    if (fd == -1) {
        perror("open gid_map");
        return 1;
    }
    if (write(fd, map, strlen(map)) == -1) {
        perror("write gid_map");
        close(fd);
        return 1;
    }
    close(fd);

    // 6. Execute the target command
    // In this architecture, the Go Bootstrap code passes the target binary 
    // as the first element of the argv array.
    // Therefore, argv[0] is the path to the binary we want to execute.
    if (argv[0] == NULL) {
        fprintf(stderr, "No target binary provided in argv[0]\\n");
        return 1;
    }

    // Prepare a new argv for the target command.
    // We want the target binary to see itself as argv[0].
    // The current argv is [target_binary, arg1, arg2, ...].
    // execv expects argv[0] to be the filename, and the rest as arguments.
    // This is already the case here, but let's be explicit.
    if (execv(argv[0], argv) == -1) {
        perror("execv failed");
        return 1;
    }
    
    return 0;
}