aboutsummaryrefslogtreecommitdiffstats
path: root/src/fseccomp
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2022-07-19 15:19:24 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2022-07-23 16:21:14 +0200
commit87afef810c2dfbf67420dc76a67c707fbb7353db (patch)
treed44aed25d9c050967eb6abe31b4081c0956f4a74 /src/fseccomp
parentprotocol filter: add x32 ABI handling (diff)
downloadfirejail-87afef810c2dfbf67420dc76a67c707fbb7353db.tar.gz
firejail-87afef810c2dfbf67420dc76a67c707fbb7353db.tar.zst
firejail-87afef810c2dfbf67420dc76a67c707fbb7353db.zip
introduce new option restrict-namespaces
Diffstat (limited to 'src/fseccomp')
-rw-r--r--src/fseccomp/fseccomp.h4
-rw-r--r--src/fseccomp/main.c6
-rw-r--r--src/fseccomp/namespaces.c197
3 files changed, 207 insertions, 0 deletions
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h
index 65337da2a..5911b5156 100644
--- a/src/fseccomp/fseccomp.h
+++ b/src/fseccomp/fseccomp.h
@@ -61,6 +61,10 @@ void seccomp_keep(const char *fname1, const char *fname2, char *list, bool nativ
61void memory_deny_write_execute(const char *fname); 61void memory_deny_write_execute(const char *fname);
62void memory_deny_write_execute_32(const char *fname); 62void memory_deny_write_execute_32(const char *fname);
63 63
64// namespaces.c
65void deny_ns(const char *fname, const char *list);
66void deny_ns_32(const char *fname, const char *list);
67
64// seccomp_print 68// seccomp_print
65void filter_print(const char *fname); 69void filter_print(const char *fname);
66 70
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c
index 48665ab71..01d7dd8cf 100644
--- a/src/fseccomp/main.c
+++ b/src/fseccomp/main.c
@@ -48,6 +48,8 @@ static void usage(void) {
48 printf("\tfseccomp keep32 file1 file2 list\n"); 48 printf("\tfseccomp keep32 file1 file2 list\n");
49 printf("\tfseccomp memory-deny-write-execute file\n"); 49 printf("\tfseccomp memory-deny-write-execute file\n");
50 printf("\tfseccomp memory-deny-write-execute.32 file\n"); 50 printf("\tfseccomp memory-deny-write-execute.32 file\n");
51 printf("\tfseccomp restrict-namespaces file list\n");
52 printf("\tfseccomp restrict-namespaces.32 file list\n");
51} 53}
52 54
53int main(int argc, char **argv) { 55int main(int argc, char **argv) {
@@ -135,6 +137,10 @@ printf("\n");
135 memory_deny_write_execute(argv[2]); 137 memory_deny_write_execute(argv[2]);
136 else if (argc == 3 && strcmp(argv[1], "memory-deny-write-execute.32") == 0) 138 else if (argc == 3 && strcmp(argv[1], "memory-deny-write-execute.32") == 0)
137 memory_deny_write_execute_32(argv[2]); 139 memory_deny_write_execute_32(argv[2]);
140 else if (argc == 4 && strcmp(argv[1], "restrict-namespaces") == 0)
141 deny_ns(argv[2], argv[3]);
142 else if (argc == 4 && strcmp(argv[1], "restrict-namespaces.32") == 0)
143 deny_ns_32(argv[2], argv[3]);
138 else { 144 else {
139 fprintf(stderr, "Error fseccomp: invalid arguments\n"); 145 fprintf(stderr, "Error fseccomp: invalid arguments\n");
140 return 1; 146 return 1;
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}