0 /* See LICENSE for license details. */
1 #include "sandbox.h"
2 #include <unistd.h>
3 #include <stdio.h>
4
5 #ifndef NO_SANDBOX
6
7 #ifdef __OpenBSD__
8 #define SANDBOXED
9 int
10 sandbox_start()
11 {
12 unveil("download", "rwc");
13 unveil(NULL, NULL);
14 pledge("stdio inet rpath wpath cpath", NULL);
15 return 0;
16 }
17 #endif
18
19 #ifdef __linux__
20 #define SANDBOXED
21 #include <sys/syscall.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <stddef.h>
28 #include <stdint.h>
29 #include <sys/prctl.h>
30 #include <linux/seccomp.h>
31 #include <linux/filter.h>
32 #include <linux/unistd.h>
33 long syscall(long number, ...); /* fix warning */
34
35 #if ENABLE_LANDLOCK || \
36 (!defined(DISABLE_LANDLOCK) && __has_include(<linux/landlock.h>))
37 #include <linux/landlock.h>
38 #define ENABLE_LANDLOCK
39 #endif
40
41 #define SC_ALLOW_(nr) \
42 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, nr, 0, 1), \
43 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
44 #define SC_ALLOW(nr) \
45 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_##nr, 0, 1), \
46 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
47 #define SC_ALLOW_ARG(_nr, _arg, _val) \
48 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (_nr), 0, 6), \
49 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
50 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_LO), \
51 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
52 ((_val) & 0xffffffff), 0, 3), \
53 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
54 offsetof(struct seccomp_data, args[(_arg)]) + SC_ARG_HI), \
55 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, \
56 (((uint32_t)((uint64_t)(_val) >> 32)) & 0xffffffff), 0, 1), \
57 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), \
58 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, \
59 offsetof(struct seccomp_data, nr))
60
61 struct sock_filter filter[] = {
62 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
63 (offsetof(struct seccomp_data, arch))),
64 BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
65 (offsetof(struct seccomp_data, nr))),
66 SC_ALLOW(fstat),
67 SC_ALLOW(stat),
68 SC_ALLOW(setsockopt),
69 SC_ALLOW(accept),
70 SC_ALLOW(listen),
71 SC_ALLOW(bind),
72 SC_ALLOW(mkdir),
73 SC_ALLOW(read),
74 SC_ALLOW(write),
75 SC_ALLOW(readv),
76 SC_ALLOW(writev),
77 SC_ALLOW(creat),
78 SC_ALLOW(sendfile),
79 SC_ALLOW(open),
80 SC_ALLOW(openat),
81 SC_ALLOW(ioctl),
82 SC_ALLOW(close),
83 SC_ALLOW(exit),
84 SC_ALLOW(exit_group),
85 SC_ALLOW(futex),
86 SC_ALLOW(newfstatat),
87 SC_ALLOW(fcntl),
88 SC_ALLOW(lseek),
89 SC_ALLOW(mprotect),
90 SC_ALLOW(pread64),
91 SC_ALLOW(sendto),
92 SC_ALLOW(recvfrom),
93 SC_ALLOW(socket),
94 SC_ALLOW(getsockopt),
95 SC_ALLOW(poll),
96 SC_ALLOW(mmap),
97 SC_ALLOW(munmap),
98 BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
99 };
100
101 #ifdef ENABLE_LANDLOCK
102
103 static int
104 landlock_create_ruleset(const struct landlock_ruleset_attr *attr,
105 size_t size, uint32_t flags)
106 {
107 return syscall(__NR_landlock_create_ruleset, attr, size, flags);
108 }
109
110 static int
111 landlock_add_rule(int ruleset_fd, enum landlock_rule_type type,
112 const void *attr, uint32_t flags)
113 {
114 return syscall(__NR_landlock_add_rule, ruleset_fd, type, attr, flags);
115 }
116
117 static int
118 landlock_restrict_self(int ruleset_fd, __u32 flags)
119 {
120 return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
121 }
122
123 int
124 landlock_unveil(int landlock_fd, int fd, int perms)
125 {
126 int ret, err;
127 struct landlock_path_beneath_attr attr = {0};
128 attr.allowed_access = perms;
129 attr.parent_fd = fd;
130
131 ret = landlock_add_rule(landlock_fd,
132 LANDLOCK_RULE_PATH_BENEATH, &attr, 0);
133 err = errno;
134 close(attr.parent_fd);
135 errno = err;
136 return ret;
137 }
138
139 #include <fcntl.h>
140 int
141 landlock_unveil_path(int landlock_fd, const char* path, int perms)
142 {
143 int fd = open(path, 0);
144 if (fd < 0) return -1;
145 return landlock_unveil(landlock_fd, fd, perms);
146 }
147
148 int
149 landlock_init()
150 {
151 struct landlock_ruleset_attr attr = {0};
152 attr.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
153 LANDLOCK_ACCESS_FS_WRITE_FILE;
154 return landlock_create_ruleset(&attr, sizeof(attr), 0);
155 }
156
157 int
158 landlock_apply(int fd)
159 {
160 int ret = landlock_restrict_self(fd, 0);
161 int err = errno;
162 close(fd);
163 errno = err;
164 return ret;
165 }
166 #endif
167
168 int
169 sandbox_start()
170 {
171 struct sock_fprog prog = {0};
172 int llfd, download;
173
174 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
175 printf("PR_SET_NO_NEW_PRIVS failed\n");
176 return -1;
177 }
178 #ifdef ENABLE_LANDLOCK
179 llfd = landlock_init();
180 if (llfd < 0) {
181 printf("Failed to initialize landlock : %s\n",
182 strerror(errno));
183 printf("The filesystem won't be hidden from the program\n");
184 goto skip_landlock;
185 }
186 download = landlock_unveil_path(llfd, "download",
187 LANDLOCK_ACCESS_FS_READ_FILE |
188 LANDLOCK_ACCESS_FS_WRITE_FILE);
189 if (download) {
190 printf("landlock, failed to unveil : %s\n", strerror(errno));
191 return -1;
192 }
193 if (landlock_apply(llfd)) {
194 printf("landlock, failed to restrict process : %s\n",
195 strerror(errno));
196 return -1;
197 }
198 skip_landlock:;
199 #endif
200 prog.len = (unsigned short)(sizeof(filter) / sizeof (filter[0])),
201 prog.filter = filter;
202 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0)) {
203 printf("Failed to enable seccomp\n");
204 return -1;
205 }
206 return 0;
207 }
208 #endif
209 #endif
210
211 #ifndef SANDBOXED
212 int
213 sandbox_start()
214 {
215 printf("No sandbox available on your system\n");
216 return 0;
217 }
218 #endif
219