aboutsummaryrefslogtreecommitdiffstats
path: root/src/fseccomp/namespaces.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fseccomp/namespaces.c')
-rw-r--r--src/fseccomp/namespaces.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/fseccomp/namespaces.c b/src/fseccomp/namespaces.c
new file mode 100644
index 000000000..3df23dcff
--- /dev/null
+++ b/src/fseccomp/namespaces.c
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 2014-2022 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20#define _GNU_SOURCE
21#include "fseccomp.h"
22#include "../include/seccomp.h"
23#include <sys/syscall.h>
24
25#include <sched.h>
26#ifndef CLONE_NEWCGROUP
27#define CLONE_NEWCGROUP 0x02000000
28#endif
29#ifndef CLONE_NEWTIME
30#define CLONE_NEWTIME 0x00000080
31#endif
32
33// 64-bit architectures
34#if INTPTR_MAX == INT64_MAX
35#if defined __x86_64__
36// i386 syscalls
37#define clone_32 120
38#define clone3_32 435
39#define unshare_32 310
40#define setns_32 346
41#else
42#warning 32 bit namespaces filter not implemented yet for your architecture
43#endif
44#endif
45
46
47static int build_ns_mask(const char *list) {
48 int mask = 0;
49
50 char *dup = strdup(list);
51 if (!dup)
52 errExit("strdup");
53
54 char *token = strtok(dup, ",");
55 while (token) {
56 if (strcmp(token, "cgroup") == 0)
57 mask |= CLONE_NEWCGROUP;
58 else if (strcmp(token, "ipc") == 0)
59 mask |= CLONE_NEWIPC;
60 else if (strcmp(token, "net") == 0)
61 mask |= CLONE_NEWNET;
62 else if (strcmp(token, "mnt") == 0)
63 mask |= CLONE_NEWNS;
64 else if (strcmp(token, "pid") == 0)
65 mask |= CLONE_NEWPID;
66 else if (strcmp(token, "time") == 0)
67 mask |= CLONE_NEWTIME;
68 else if (strcmp(token, "user") == 0)
69 mask |= CLONE_NEWUSER;
70 else if (strcmp(token, "uts") == 0)
71 mask |= CLONE_NEWUTS;
72 else {
73 fprintf(stderr, "Error fseccomp: %s is not a valid namespace\n", token);
74 exit(1);
75 }
76
77 token = strtok(NULL, ",");
78 }
79
80 free(dup);
81 return mask;
82}
83
84void deny_ns(const char *fname, const char *list) {
85 int mask = build_ns_mask(list);
86 // CLONE_NEWTIME means something different for clone
87 // create a second mask without it
88 int clone_mask = mask & ~CLONE_NEWTIME;
89
90 // open file
91 int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
92 if (fd < 0) {
93 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
94 exit(1);
95 }
96
97 filter_init(fd, true);
98
99 // build filter
100 struct sock_filter filter[] = {
101#ifdef SYS_clone
102 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_clone, 0, 4),
103 // s390 has first and second argument flipped
104#if defined __s390__
105 EXAMINE_ARGUMENT(1),
106#else
107 EXAMINE_ARGUMENT(0),
108#endif
109 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, clone_mask, 0, 1),
110 KILL_OR_RETURN_ERRNO,
111 RETURN_ALLOW,
112#endif
113#ifdef SYS_clone3
114 // cannot inspect clone3 argument because
115 // seccomp does not dereference pointers
116 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_clone3, 0, 1),
117 RETURN_ERRNO(ENOSYS), // hint to use clone instead
118#endif
119#ifdef SYS_unshare
120 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_unshare, 0, 4),
121 EXAMINE_ARGUMENT(0),
122 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, mask, 0, 1),
123 KILL_OR_RETURN_ERRNO,
124 RETURN_ALLOW,
125#endif
126#ifdef SYS_setns
127 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_setns, 0, 4),
128 EXAMINE_ARGUMENT(1),
129 // always fail if argument is zero
130 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 1, 0),
131 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, mask, 0, 1),
132 KILL_OR_RETURN_ERRNO,
133 RETURN_ALLOW
134#endif
135 };
136 write_to_file(fd, filter, sizeof(filter));
137
138 filter_end_blacklist(fd);
139
140 // close file
141 close(fd);
142}
143
144void deny_ns_32(const char *fname, const char *list) {
145 int mask = build_ns_mask(list);
146 // CLONE_NEWTIME means something different for clone
147 // create a second mask without it
148 int clone_mask = mask & ~CLONE_NEWTIME;
149
150 // open file
151 int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
152 if (fd < 0) {
153 fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname);
154 exit(1);
155 }
156
157 filter_init(fd, false);
158
159 // build filter
160 struct sock_filter filter[] = {
161#ifdef clone_32
162 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, clone_32, 0, 4),
163 EXAMINE_ARGUMENT(0),
164 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, clone_mask, 0, 1),
165 KILL_OR_RETURN_ERRNO,
166 RETURN_ALLOW,
167#endif
168#ifdef clone3_32
169 // cannot inspect clone3 argument because
170 // seccomp does not dereference pointers
171 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, clone3_32, 0, 1),
172 RETURN_ERRNO(ENOSYS), // hint to use clone instead
173#endif
174#ifdef unshare_32
175 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, unshare_32, 0, 4),
176 EXAMINE_ARGUMENT(0),
177 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, mask, 0, 1),
178 KILL_OR_RETURN_ERRNO,
179 RETURN_ALLOW,
180#endif
181#ifdef setns_32
182 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, setns_32, 0, 4),
183 EXAMINE_ARGUMENT(1),
184 // always fail if argument is zero
185 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 1, 0),
186 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, mask, 0, 1),
187 KILL_OR_RETURN_ERRNO,
188 RETURN_ALLOW
189#endif
190 };
191 write_to_file(fd, filter, sizeof(filter));
192
193 filter_end_blacklist(fd);
194
195 // close file
196 close(fd);
197}