Skip to content

Commit 42e4a30

Browse files
committed
add wrap.c - A small bubblewrap like program
from fosslinux/live-bootstrap#339
1 parent c1bd4ab commit 42e4a30

2 files changed

Lines changed: 204 additions & 0 deletions

File tree

mescc-tools-extra.kaem

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ CC cp.c -o ${BINDIR}/cp${EXE_SUFFIX}
3939
CC chmod.c -o ${BINDIR}/chmod${EXE_SUFFIX}
4040
CC rm.c -o ${BINDIR}/rm${EXE_SUFFIX}
4141
CC replace.c -o ${BINDIR}/replace${EXE_SUFFIX}
42+
CC wrap.c -o ${BINDIR}/wrap${EXE_SUFFIX}

wrap.c

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/* SPDX-FileCopyrightText: 2023 Max Hearnden <max@hearnden.org.uk> */
2+
/* SPDX-License-Identifier: GPL-3.0-or-later */
3+
4+
5+
#define CLONE_NEWUSER 0x10000000
6+
#define CLONE_NEWNS 0x00020000
7+
#define MS_BIND 4096
8+
#define MS_REC 16384
9+
#define MNT_DETACH 0x00000002
10+
#define _GNU_SOURCE
11+
12+
#include <stdio.h>
13+
#include <string.h>
14+
#include <stdlib.h>
15+
16+
#include <sys/stat.h>
17+
18+
#include <fcntl.h>
19+
#include <unistd.h>
20+
21+
#ifdef __M2__
22+
23+
#include <bootstrappable.h>
24+
25+
#else
26+
27+
extern int unshare(int flags);
28+
29+
extern int mount(const char *source, const char *target,
30+
const char *filesystemtype, unsigned long mountflags, const void *data);
31+
32+
#endif
33+
34+
void touch(char *path) {
35+
int fd = open(path, O_CREAT, 0777);
36+
if (fd == -1) {
37+
fputs("Failed to create file ", stderr);
38+
fputs(path, stderr);
39+
fputc('\n', stderr);
40+
exit(EXIT_FAILURE);
41+
}
42+
if (close(fd) != 0) {
43+
fputs("Failed to close file ", stderr);
44+
fputs(path, stderr);
45+
fputc('\n', stderr);
46+
exit(EXIT_FAILURE);
47+
}
48+
}
49+
50+
void mkmount(
51+
char *source, char *target, char *filesystemtype,
52+
unsigned mountflags, void *data, int type
53+
) {
54+
int r = 0;
55+
if (type) {
56+
r = mkdir(target, 0755);
57+
} else {
58+
touch(target);
59+
}
60+
if (r != 0 && r != -17) {
61+
fputs("Failed to create mountpoint ", stderr);
62+
fputs(target, stderr);
63+
fputc('\n', stderr);
64+
exit(EXIT_FAILURE);
65+
}
66+
67+
r = mount(source, target, filesystemtype, mountflags, data);
68+
69+
if (r != 0) {
70+
fputs("Failed to mount directory ", stderr);
71+
fputs(target, stderr);
72+
fputc('\n', stderr);
73+
exit(EXIT_FAILURE);
74+
}
75+
}
76+
77+
void set_map(int parent_id, char *path) {
78+
int fd = open(path, O_WRONLY, 0);
79+
if (fd == -1) {
80+
fputs("Failed to open map file ", stderr);
81+
fputs(path, stderr);
82+
fputc('\n', stderr);
83+
exit(EXIT_FAILURE);
84+
}
85+
86+
char *map_contents = calloc(38, sizeof(char));
87+
88+
#ifdef __M2__
89+
strcpy(map_contents, "0 ");
90+
char *parent_id_str = int2str(parent_id, 10, 0);
91+
strcat(map_contents, parent_id_str);
92+
strcat(map_contents, " 1");
93+
#else
94+
snprintf(map_contents, 38, "0 %i 1", parent_id);
95+
#endif
96+
write(fd, map_contents, strlen(map_contents));
97+
write(STDOUT_FILENO, map_contents, strlen(map_contents));
98+
free(map_contents);
99+
close(fd);
100+
}
101+
102+
void deny_setgroups() {
103+
int fd = open("/proc/self/setgroups", O_WRONLY, 0777);
104+
if(fd == -1) {
105+
fputs("Failed to open /proc/self/setgroups\n", stderr);
106+
exit(EXIT_FAILURE);
107+
}
108+
write(fd, "deny", 4);
109+
close(fd);
110+
}
111+
112+
int main(int argc, char **argv) {
113+
if(argc <= 1) {
114+
fputs("Expected at least one argument: command\n", stderr);
115+
exit(EXIT_FAILURE);
116+
}
117+
char *cwd = get_current_dir_name();
118+
/* Do nothing if cwd is already root */
119+
if (strcmp(cwd, "/")) {
120+
int uid = geteuid();
121+
int gid = getegid();
122+
/* Don't create a user and mount namespace if we are already root */
123+
if (uid != 0) {
124+
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0) {
125+
fputs("Failed to create user and mount namespaces\n", stderr);
126+
exit(EXIT_FAILURE);
127+
}
128+
/* Prevent the use of setgroups and make gid_map writeable */
129+
deny_setgroups();
130+
/* Map the root user in the user namespace to our user id */
131+
set_map(uid, "/proc/self/uid_map");
132+
/* Map the root group in the user namespace to our group id */
133+
set_map(gid, "/proc/self/gid_map");
134+
}
135+
int r = mkdir("dev", 0755);
136+
if (r != 0 && r != -17) {
137+
fputs("Failed to create dev folder\n", stderr);
138+
exit(EXIT_FAILURE);
139+
}
140+
#if !__uefi__
141+
mkmount ("/dev/null", "dev/null", "", MS_BIND, NULL, 0);
142+
mkmount ("/dev/zero", "dev/zero", "", MS_BIND, NULL, 0);
143+
mkmount ("/dev/random", "dev/random", "", MS_BIND, NULL, 0);
144+
mkmount ("/dev/urandom", "dev/urandom", "", MS_BIND, NULL, 0);
145+
mkmount ("/dev/ptmx", "dev/ptmx", "", MS_BIND, NULL, 0);
146+
mkmount ("/dev/tty", "dev/tty", "", MS_BIND, NULL, 0);
147+
mkmount ("tmpfs", "dev/shm", "tmpfs", 0, NULL, 1);
148+
mkmount ("/proc", "proc", "", MS_BIND | MS_REC, NULL, 1);
149+
mkmount ("/sys", "sys", "", MS_BIND | MS_REC, NULL, 1);
150+
mkmount ("tmpfs", "tmp", "tmpfs", 0, NULL, 1);
151+
#endif
152+
if (chroot (".") != 0) {
153+
fputs("Failed to chroot into .\n", stderr);
154+
exit(EXIT_FAILURE);
155+
}
156+
}
157+
free(cwd);
158+
159+
160+
char **newenv = malloc(3 * sizeof(char *));
161+
int newenv_index = 0;
162+
if (newenv == NULL) {
163+
fputs("Failed to allocate space for new environment\n", stderr);
164+
exit(EXIT_FAILURE);
165+
}
166+
167+
char *ARCH = getenv("ARCH");
168+
if (ARCH != NULL) {
169+
newenv[0] = malloc(6 + strlen(ARCH));
170+
if (newenv[0] == NULL) {
171+
fputs("Failed to allocate space for new environment\n", stderr);
172+
exit(EXIT_FAILURE);
173+
}
174+
strcpy(newenv[0], "ARCH=");
175+
strcpy(newenv[0] + 5, ARCH);
176+
newenv_index += 1;
177+
}
178+
179+
char *ARCH_DIR = getenv("ARCH_DIR");
180+
if (ARCH_DIR != NULL) {
181+
newenv[newenv_index] = malloc(10 + strlen(ARCH_DIR));
182+
if (newenv[newenv_index] == NULL) {
183+
fputs("Failed to allocate space for new environment\n", stderr);
184+
exit(EXIT_FAILURE);
185+
}
186+
strcpy(newenv[newenv_index], "ARCH_DIR=");
187+
strcpy(newenv[newenv_index] + 9, ARCH_DIR);
188+
newenv_index += 1;
189+
}
190+
191+
newenv[newenv_index] = NULL;
192+
193+
194+
#ifdef __M2__
195+
#if __uefi__
196+
return spawn (argv[1], argv + sizeof(char *), newenv);
197+
#else
198+
return execve (argv[1], argv + sizeof(char *), newenv);
199+
#endif
200+
#else
201+
return execve (argv[1], argv + 1, newenv);
202+
#endif
203+
}

0 commit comments

Comments
 (0)