aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Stephani2020-12-17 11:20:55 +0100
committerPhilipp Stephani2020-12-29 14:37:51 +0100
commit202a61d09cddf420ce2f18f86aea741f086022fd (patch)
tree567adc566589c3cda9cb3b4e615e575c34f3ec1c
parent2334f9bfa3f54a606d1748ab86ee9fd481369d7a (diff)
downloademacs-scratch/seccomp.tar.gz
emacs-scratch/seccomp.zip
Add a helper binary to create a basic Secure Computing filter.scratch/seccomp
The binary uses the 'seccomp' helper library. The library isn't needed to load the generated Secure Computing filter. * configure.ac: Check for 'seccomp' header and library. * lib-src/seccomp-filter.c: New helper binary to generate a generic Secure Computing filter for GNU/Linux. * lib-src/Makefile.in (DONT_INSTALL): Add 'seccomp-filter' helper binary if possible. (all): Add Secure Computing filter file if possible. (seccomp-filter$(EXEEXT)): Compile helper binary. (seccomp-filter.bpf seccomp-filter.pfc): Generate filter files. * test/src/emacs-tests.el (emacs-tests/seccomp/allows-stdout) (emacs-tests/seccomp/forbids-subprocess): New unit tests. * test/Makefile.in (src/emacs-tests.log): Add dependency on the helper binary.
-rw-r--r--.gitignore5
-rw-r--r--configure.ac5
-rw-r--r--lib-src/Makefile.in19
-rw-r--r--lib-src/seccomp-filter.c321
-rw-r--r--test/Makefile.in2
l---------test/src/emacs-resources/seccomp-filter.bpf1
-rw-r--r--test/src/emacs-tests.el45
7 files changed, 398 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index bf7e9349813..8c8b1f7584c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -187,6 +187,7 @@ lib-src/make-docfile
187lib-src/make-fingerprint 187lib-src/make-fingerprint
188lib-src/movemail 188lib-src/movemail
189lib-src/profile 189lib-src/profile
190lib-src/seccomp-filter
190lib-src/test-distrib 191lib-src/test-distrib
191lib-src/update-game-score 192lib-src/update-game-score
192nextstep/Cocoa/Emacs.base/Contents/Info.plist 193nextstep/Cocoa/Emacs.base/Contents/Info.plist
@@ -298,3 +299,7 @@ nt/emacs.rc
298nt/emacsclient.rc 299nt/emacsclient.rc
299src/gdb.ini 300src/gdb.ini
300/var/ 301/var/
302
303# Seccomp filter files.
304lib-src/seccomp-filter.bpf
305lib-src/seccomp-filter.pfc
diff --git a/configure.ac b/configure.ac
index 4dbcda36e86..4945307975b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4186,6 +4186,11 @@ AC_SUBST([LIBS_MAIL])
4186 4186
4187AC_CHECK_HEADERS([linux/seccomp.h], [HAVE_SECCOMP=yes]) 4187AC_CHECK_HEADERS([linux/seccomp.h], [HAVE_SECCOMP=yes])
4188 4188
4189LIBSECCOMP=
4190AC_CHECK_HEADER([seccomp.h],
4191 [AC_CHECK_LIB([seccomp], [seccomp_init], [LIBSECCOMP=-lseccomp])])
4192AC_SUBST([LIBSECCOMP])
4193
4189OLD_LIBS=$LIBS 4194OLD_LIBS=$LIBS
4190LIBS="$LIB_PTHREAD $LIB_MATH $LIBS" 4195LIBS="$LIB_PTHREAD $LIB_MATH $LIBS"
4191AC_CHECK_FUNCS(accept4 fchdir gethostname \ 4196AC_CHECK_FUNCS(accept4 fchdir gethostname \
diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in
index a2d27eab001..72a980e4de3 100644
--- a/lib-src/Makefile.in
+++ b/lib-src/Makefile.in
@@ -209,6 +209,12 @@ LIB_EACCESS=@LIB_EACCESS@
209## empty or -lwsock2 for MinGW 209## empty or -lwsock2 for MinGW
210LIB_WSOCK32=@LIB_WSOCK32@ 210LIB_WSOCK32=@LIB_WSOCK32@
211 211
212LIBSECCOMP=@LIBSECCOMP@
213
214ifneq ($(LIBSECCOMP),)
215DONT_INSTALL += seccomp-filter$(EXEEXT)
216endif
217
212## Extra libraries to use when linking movemail. 218## Extra libraries to use when linking movemail.
213LIBS_MOVE = $(LIBS_MAIL) $(KRB4LIB) $(DESLIB) $(KRB5LIB) $(CRYPTOLIB) \ 219LIBS_MOVE = $(LIBS_MAIL) $(KRB4LIB) $(DESLIB) $(KRB5LIB) $(CRYPTOLIB) \
214 $(COM_ERRLIB) $(LIBHESIOD) $(LIBRESOLV) $(LIB_WSOCK32) 220 $(COM_ERRLIB) $(LIBHESIOD) $(LIBRESOLV) $(LIB_WSOCK32)
@@ -238,6 +244,10 @@ config_h = ../src/config.h $(srcdir)/../src/conf_post.h
238 244
239all: ${EXE_FILES} ${SCRIPTS} 245all: ${EXE_FILES} ${SCRIPTS}
240 246
247ifneq ($(LIBSECCOMP),)
248all: seccomp-filter.bpf
249endif
250
241.PHONY: all need-blessmail maybe-blessmail 251.PHONY: all need-blessmail maybe-blessmail
242 252
243LOADLIBES = ../lib/libgnu.a $(LIBS_SYSTEM) 253LOADLIBES = ../lib/libgnu.a $(LIBS_SYSTEM)
@@ -420,4 +430,13 @@ update-game-score${EXEEXT}: ${srcdir}/update-game-score.c $(NTLIB) $(config_h)
420emacsclient.res: ../nt/emacsclient.rc $(NTINC)/../icons/emacs.ico 430emacsclient.res: ../nt/emacsclient.rc $(NTINC)/../icons/emacs.ico
421 $(AM_V_RC)$(WINDRES) -O coff --include-dir=$(NTINC)/.. -o $@ $< 431 $(AM_V_RC)$(WINDRES) -O coff --include-dir=$(NTINC)/.. -o $@ $<
422 432
433ifneq ($(LIBSECCOMP),)
434seccomp-filter$(EXEEXT): $(srcdir)/seccomp-filter.c $(config_h)
435 $(AM_V_CCLD)$(CC) $(ALL_CFLAGS) $< $(LIBSECCOMP) -o $@
436
437seccomp-filter.bpf seccomp-filter.pfc: seccomp-filter$(EXEEXT)
438 $(AM_V_GEN)./seccomp-filter$(EXEEXT) \
439 seccomp-filter.bpf seccomp-filter.pfc
440endif
441
423## Makefile ends here. 442## Makefile ends here.
diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c
new file mode 100644
index 00000000000..9918fb025ef
--- /dev/null
+++ b/lib-src/seccomp-filter.c
@@ -0,0 +1,321 @@
1/* Generate a Secure Computing filter definition file.
2
3Copyright (C) 2020 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation, either version 3 of the License, or (at your
10option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see
19<https://www.gnu.org/licenses/>. */
20
21/* This program creates a small Secure Computing filter usable for a
22typical minimal Emacs sandbox. See the man page for `seccomp' for
23details about Secure Computing filters. This program requires the
24`libseccomp' library. However, the resulting filter file requires
25only a Linux kernel supporting the Secure Computing extension.
26
27Usage:
28
29 seccomp-filter out.bpf out.pfc
30
31This writes the raw `struct sock_filter' array to out.bpf and a
32human-readable representation to out.pfc. */
33
34#include "config.h"
35
36#include <errno.h>
37#include <limits.h>
38#include <stdarg.h>
39#include <stdbool.h>
40#include <stdlib.h>
41#include <stdint.h>
42#include <stdio.h>
43
44#include <sys/ioctl.h>
45#include <sys/mman.h>
46#include <sys/prctl.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <linux/futex.h>
50#include <fcntl.h>
51#include <sched.h>
52#include <seccomp.h>
53#include <unistd.h>
54
55#include "verify.h"
56
57static ATTRIBUTE_FORMAT_PRINTF (2, 3) _Noreturn void
58fail (int error, const char *format, ...)
59{
60 va_list ap;
61 va_start (ap, format);
62 if (error == 0)
63 vfprintf (stderr, format, ap);
64 else
65 {
66 char buffer[1000];
67 vsnprintf (buffer, sizeof buffer, format, ap);
68 errno = error;
69 perror (buffer);
70 }
71 va_end (ap);
72 fflush (NULL);
73 exit (EXIT_FAILURE);
74}
75
76/* This binary is trivial, so we use a single global filter context
77 object that we release using `atexit'. */
78
79static scmp_filter_ctx ctx;
80
81static void
82release_context (void)
83{
84 seccomp_release (ctx);
85}
86
87/* Wrapper functions and macros for libseccomp functions. We exit
88 immediately upon any error to avoid error checking noise. */
89
90static void
91set_attribute (enum scmp_filter_attr attr, uint32_t value)
92{
93 int status = seccomp_attr_set (ctx, attr, value);
94 if (status < 0)
95 fail (-status, "seccomp_attr_set (ctx, %u, %u)", attr, value);
96}
97
98/* Like `seccomp_rule_add (ACTION, SYSCALL, ...)', except that you
99 don't have to specify the number of comparator arguments, and any
100 failure will exit the process. */
101
102#define RULE(action, syscall, ...) \
103 do \
104 { \
105 const struct scmp_arg_cmp arg_array[] = {__VA_ARGS__}; \
106 enum { arg_cnt = sizeof arg_array / sizeof *arg_array }; \
107 int status = seccomp_rule_add_array (ctx, (action), (syscall), \
108 arg_cnt, arg_array); \
109 if (status < 0) \
110 fail (-status, "seccomp_rule_add_array (%s, %s, %d, {%s})", \
111 #action, #syscall, arg_cnt, #__VA_ARGS__); \
112 } \
113 while (false)
114
115static void
116export_filter (const char *file,
117 int (*function) (const scmp_filter_ctx, int),
118 const char *name)
119{
120 int fd = TEMP_FAILURE_RETRY (
121 open (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC,
122 0644));
123 if (fd < 0)
124 fail (errno, "open %s", file);
125 int status = function (ctx, fd);
126 if (status < 0)
127 fail (-status, "%s", name);
128 if (close (fd) != 0)
129 fail (errno, "close");
130}
131
132#define EXPORT_FILTER(file, function) \
133 export_filter ((file), (function), #function)
134
135int
136main (int argc, char **argv)
137{
138 if (argc != 3)
139 fail (0, "usage: %s out.bpf out.pfc", argv[0]);
140
141 /* Any unhandled syscall should abort the Emacs process. */
142 ctx = seccomp_init (SCMP_ACT_KILL_PROCESS);
143 if (ctx == NULL)
144 fail (0, "seccomp_init");
145 atexit (release_context);
146
147 /* We want to abort immediately if the architecture is unknown. */
148 set_attribute (SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_KILL_PROCESS);
149 set_attribute (SCMP_FLTATR_CTL_NNP, 1);
150 set_attribute (SCMP_FLTATR_CTL_TSYNC, 1);
151 set_attribute (SCMP_FLTATR_CTL_LOG, 0);
152
153 verify (CHAR_BIT == 8);
154 verify (sizeof (int) == 4 && INT_MIN == INT32_MIN
155 && INT_MAX == INT32_MAX);
156 verify (sizeof (void *) == 8);
157 verify ((uintptr_t) NULL == 0);
158
159 /* Allow a clean exit. */
160 RULE (SCMP_ACT_ALLOW, SCMP_SYS (exit));
161 RULE (SCMP_ACT_ALLOW, SCMP_SYS (exit_group));
162
163 /* Allow `mmap' and friends. This is necessary for dynamic loading,
164 reading the portable dump file, and thread creation. We don't
165 allow pages to be both writable and executable. */
166 verify (MAP_PRIVATE != 0);
167 verify (MAP_SHARED != 0);
168 RULE (SCMP_ACT_ALLOW, SCMP_SYS (mmap),
169 SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
170 ~(PROT_NONE | PROT_READ | PROT_WRITE)),
171 /* Only support known flags. MAP_DENYWRITE is ignored, but
172 some versions of the dynamic loader still use it. Also
173 allow allocating thread stacks. */
174 SCMP_A3_32 (SCMP_CMP_MASKED_EQ,
175 ~(MAP_PRIVATE | MAP_FILE | MAP_ANONYMOUS
176 | MAP_FIXED | MAP_DENYWRITE | MAP_STACK
177 | MAP_NORESERVE),
178 0));
179 RULE (SCMP_ACT_ALLOW, SCMP_SYS (mmap),
180 SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
181 ~(PROT_NONE | PROT_READ | PROT_EXEC)),
182 /* Only support known flags. MAP_DENYWRITE is ignored, but
183 some versions of the dynamic loader still use it. */
184 SCMP_A3_32 (SCMP_CMP_MASKED_EQ,
185 ~(MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
186 | MAP_DENYWRITE),
187 0));
188 RULE (SCMP_ACT_ALLOW, SCMP_SYS (munmap));
189 RULE (SCMP_ACT_ALLOW, SCMP_SYS (mprotect),
190 /* Don't allow making pages executable. */
191 SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
192 ~(PROT_NONE | PROT_READ | PROT_WRITE), 0));
193
194 /* Futexes are used everywhere. */
195 RULE (SCMP_ACT_ALLOW, SCMP_SYS (futex),
196 SCMP_A1_32 (SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE));
197
198 /* Allow basic dynamic memory management. */
199 RULE (SCMP_ACT_ALLOW, SCMP_SYS (brk));
200
201 /* Allow some status inquiries. */
202 RULE (SCMP_ACT_ALLOW, SCMP_SYS (uname));
203 RULE (SCMP_ACT_ALLOW, SCMP_SYS (getuid));
204 RULE (SCMP_ACT_ALLOW, SCMP_SYS (geteuid));
205 RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpid));
206 RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpgrp));
207
208 /* Allow operations on open file descriptors. File descriptors are
209 capabilities, and operating on them shouldn't cause security
210 issues. */
211 RULE (SCMP_ACT_ALLOW, SCMP_SYS (read));
212 RULE (SCMP_ACT_ALLOW, SCMP_SYS (write));
213 RULE (SCMP_ACT_ALLOW, SCMP_SYS (close));
214 RULE (SCMP_ACT_ALLOW, SCMP_SYS (lseek));
215 RULE (SCMP_ACT_ALLOW, SCMP_SYS (dup));
216 RULE (SCMP_ACT_ALLOW, SCMP_SYS (dup2));
217 RULE (SCMP_ACT_ALLOW, SCMP_SYS (fstat));
218
219 /* Allow read operations on the filesystem. If necessary, these
220 should be further restricted using mount namespaces. */
221 RULE (SCMP_ACT_ALLOW, SCMP_SYS (access));
222 RULE (SCMP_ACT_ALLOW, SCMP_SYS (faccessat));
223 RULE (SCMP_ACT_ALLOW, SCMP_SYS (stat));
224 RULE (SCMP_ACT_ALLOW, SCMP_SYS (stat64));
225 RULE (SCMP_ACT_ALLOW, SCMP_SYS (lstat));
226 RULE (SCMP_ACT_ALLOW, SCMP_SYS (lstat64));
227 RULE (SCMP_ACT_ALLOW, SCMP_SYS (fstatat64));
228 RULE (SCMP_ACT_ALLOW, SCMP_SYS (newfstatat));
229 RULE (SCMP_ACT_ALLOW, SCMP_SYS (readlink));
230 RULE (SCMP_ACT_ALLOW, SCMP_SYS (readlinkat));
231 RULE (SCMP_ACT_ALLOW, SCMP_SYS (getcwd));
232
233 /* Allow opening files, assuming they are only opened for
234 reading. */
235 verify (O_WRONLY != 0);
236 verify (O_RDWR != 0);
237 verify (O_CREAT != 0);
238 RULE (SCMP_ACT_ALLOW, SCMP_SYS (open),
239 SCMP_A1_32 (SCMP_CMP_MASKED_EQ,
240 ~(O_RDONLY | O_BINARY | O_CLOEXEC | O_PATH
241 | O_DIRECTORY),
242 0));
243 RULE (SCMP_ACT_ALLOW, SCMP_SYS (openat),
244 SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
245 ~(O_RDONLY | O_BINARY | O_CLOEXEC | O_PATH
246 | O_DIRECTORY),
247 0));
248
249 /* Allow `tcgetpgrp'. */
250 RULE (SCMP_ACT_ALLOW, SCMP_SYS (ioctl),
251 SCMP_A0_32 (SCMP_CMP_EQ, STDIN_FILENO),
252 SCMP_A1_32 (SCMP_CMP_EQ, TIOCGPGRP));
253
254 /* Allow reading (but not setting) file flags. */
255 RULE (SCMP_ACT_ALLOW, SCMP_SYS (fcntl),
256 SCMP_A1_32 (SCMP_CMP_EQ, F_GETFL));
257 RULE (SCMP_ACT_ALLOW, SCMP_SYS (fcntl64),
258 SCMP_A1_32 (SCMP_CMP_EQ, F_GETFL));
259
260 /* Allow reading random numbers from the kernel. */
261 RULE (SCMP_ACT_ALLOW, SCMP_SYS (getrandom));
262
263 /* Changing the umask is uncritical. */
264 RULE (SCMP_ACT_ALLOW, SCMP_SYS (umask));
265
266 /* Allow creation of pipes. */
267 RULE (SCMP_ACT_ALLOW, SCMP_SYS (pipe));
268 RULE (SCMP_ACT_ALLOW, SCMP_SYS (pipe2));
269
270 /* Allow reading (but not changing) resource limits. */
271 RULE (SCMP_ACT_ALLOW, SCMP_SYS (getrlimit));
272 RULE (SCMP_ACT_ALLOW, SCMP_SYS (prlimit64),
273 SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */,
274 SCMP_A2_64 (SCMP_CMP_EQ, 0) /* new_limit == NULL */);
275
276 /* Block changing resource limits, but don't crash. */
277 RULE (SCMP_ACT_ERRNO (EPERM), SCMP_SYS (prlimit64),
278 SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */,
279 SCMP_A2_64 (SCMP_CMP_NE, 0) /* new_limit != NULL */);
280
281 /* Emacs installs signal handlers, which is harmless. */
282 RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigaction));
283 RULE (SCMP_ACT_ALLOW, SCMP_SYS (rt_sigaction));
284 RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigprocmask));
285 RULE (SCMP_ACT_ALLOW, SCMP_SYS (rt_sigprocmask));
286
287 /* Allow timer support. */
288 RULE (SCMP_ACT_ALLOW, SCMP_SYS (timer_create));
289 RULE (SCMP_ACT_ALLOW, SCMP_SYS (timerfd_create));
290
291 /* Allow thread creation. See the NOTES section in the manual page
292 for the `clone' function. */
293 RULE (SCMP_ACT_ALLOW, SCMP_SYS (clone),
294 SCMP_A0_64 (SCMP_CMP_MASKED_EQ,
295 /* Flags needed to create threads. See
296 create_thread in libc. */
297 ~(CLONE_VM | CLONE_FS | CLONE_FILES
298 | CLONE_SYSVSEM | CLONE_SIGHAND | CLONE_THREAD
299 | CLONE_SETTLS | CLONE_PARENT_SETTID
300 | CLONE_CHILD_CLEARTID),
301 0));
302 RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigaltstack));
303 RULE (SCMP_ACT_ALLOW, SCMP_SYS (set_robust_list));
304
305 /* Allow setting the process name for new threads. */
306 RULE (SCMP_ACT_ALLOW, SCMP_SYS (prctl),
307 SCMP_A0_32 (SCMP_CMP_EQ, PR_SET_NAME));
308
309 /* Allow some event handling functions used by glib. */
310 RULE (SCMP_ACT_ALLOW, SCMP_SYS (eventfd));
311 RULE (SCMP_ACT_ALLOW, SCMP_SYS (eventfd2));
312 RULE (SCMP_ACT_ALLOW, SCMP_SYS (wait4));
313 RULE (SCMP_ACT_ALLOW, SCMP_SYS (poll));
314
315 /* Don't allow creating sockets (network access would be extremely
316 dangerous), but also don't crash. */
317 RULE (SCMP_ACT_ERRNO (EACCES), SCMP_SYS (socket));
318
319 EXPORT_FILTER (argv[1], seccomp_export_bpf);
320 EXPORT_FILTER (argv[2], seccomp_export_pfc);
321}
diff --git a/test/Makefile.in b/test/Makefile.in
index b6cf6493e32..670bdd6c3da 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -272,6 +272,8 @@ $(test_module): $(test_module:${SO}=.c) ../src/emacs-module.h
272 $(srcdir)/../lib/timespec.c $(srcdir)/../lib/gettime.c 272 $(srcdir)/../lib/timespec.c $(srcdir)/../lib/gettime.c
273endif 273endif
274 274
275src/emacs-tests.log: ../lib-src/seccomp-filter.c
276
275## Check that there is no 'automated' subdirectory, which would 277## Check that there is no 'automated' subdirectory, which would
276## indicate an incomplete merge from an older version of Emacs where 278## indicate an incomplete merge from an older version of Emacs where
277## the tests were arranged differently. 279## the tests were arranged differently.
diff --git a/test/src/emacs-resources/seccomp-filter.bpf b/test/src/emacs-resources/seccomp-filter.bpf
new file mode 120000
index 00000000000..b3d603d0aeb
--- /dev/null
+++ b/test/src/emacs-resources/seccomp-filter.bpf
@@ -0,0 +1 @@
../../../lib-src/seccomp-filter.bpf \ No newline at end of file
diff --git a/test/src/emacs-tests.el b/test/src/emacs-tests.el
index 7618a9c6752..e9333fe9d32 100644
--- a/test/src/emacs-tests.el
+++ b/test/src/emacs-tests.el
@@ -25,7 +25,9 @@
25 25
26(require 'cl-lib) 26(require 'cl-lib)
27(require 'ert) 27(require 'ert)
28(require 'ert-x)
28(require 'rx) 29(require 'rx)
30(require 'subr-x)
29 31
30(ert-deftest emacs-tests/seccomp/absent-file () 32(ert-deftest emacs-tests/seccomp/absent-file ()
31 (skip-unless (string-match-p (rx bow "SECCOMP" eow) 33 (skip-unless (string-match-p (rx bow "SECCOMP" eow)
@@ -128,4 +130,47 @@ to `make-temp-file', which see."
128 (concat "--seccomp=" filter)) 130 (concat "--seccomp=" filter))
129 0))))) 131 0)))))
130 132
133(ert-deftest emacs-tests/seccomp/allows-stdout ()
134 (let ((emacs
135 (expand-file-name invocation-name invocation-directory))
136 (filter (ert-resource-file "seccomp-filter.bpf"))
137 (process-environment nil))
138 (skip-unless (file-executable-p emacs))
139 (skip-unless (file-readable-p filter))
140 ;; The --seccomp option is processed early, without filename
141 ;; handlers. Therefore remote or quoted filenames wouldn't work.
142 (should-not (file-remote-p filter))
143 (cl-callf file-name-unquote filter)
144 (with-temp-buffer
145 (let ((status (call-process
146 emacs nil t nil
147 "--quick" "--batch"
148 (concat "--seccomp=" filter)
149 (format "--eval=%S" '(message "Hi")))))
150 (ert-info ((format "Process output: %s" (buffer-string)))
151 (should (eql status 0)))
152 (should (equal (string-trim (buffer-string)) "Hi"))))))
153
154(ert-deftest emacs-tests/seccomp/forbids-subprocess ()
155 (let ((emacs
156 (expand-file-name invocation-name invocation-directory))
157 (filter (ert-resource-file "seccomp-filter.bpf"))
158 (process-environment nil))
159 (skip-unless (file-executable-p emacs))
160 (skip-unless (file-readable-p filter))
161 ;; The --seccomp option is processed early, without filename
162 ;; handlers. Therefore remote or quoted filenames wouldn't work.
163 (should-not (file-remote-p filter))
164 (cl-callf file-name-unquote filter)
165 (with-temp-buffer
166 (let ((status
167 (call-process
168 emacs nil t nil
169 "--quick" "--batch"
170 (concat "--seccomp=" filter)
171 (format "--eval=%S" `(call-process ,emacs nil nil nil
172 "--version")))))
173 (ert-info ((format "Process output: %s" (buffer-string)))
174 (should-not (eql status 0)))))))
175
131;;; emacs-tests.el ends here 176;;; emacs-tests.el ends here