root/lib-src/seccomp-filter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ATTRIBUTE_FORMAT_PRINTF
  2. release_context
  3. set_attribute
  4. export_filter
  5. main

     1 /* Generate a Secure Computing filter definition file.
     2 
     3 Copyright (C) 2020-2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify it
     8 under the terms of the GNU General Public License as published by the
     9 Free Software Foundation, either version 3 of the License, or (at your
    10 option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful, but
    13 WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    15 General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along 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
    22 typical minimal Emacs sandbox.  See the man page for `seccomp' for
    23 details about Secure Computing filters.  This program requires the
    24 `libseccomp' library.  However, the resulting filter file requires
    25 only a Linux kernel supporting the Secure Computing extension.
    26 
    27 Usage:
    28 
    29   seccomp-filter out.bpf out.pfc out-exec.bpf out-exec.pfc
    30 
    31 This writes the raw `struct sock_filter' array to out.bpf and a
    32 human-readable representation to out.pfc.  Additionally, it writes
    33 variants of those files that can be used to sandbox Emacs before
    34 'execve' to out-exec.bpf and out-exec.pfc.  */
    35 
    36 #include "config.h"
    37 
    38 #include <assert.h>
    39 #include <errno.h>
    40 #include <limits.h>
    41 #include <stdarg.h>
    42 #include <stdlib.h>
    43 #include <stdint.h>
    44 #include <stdio.h>
    45 #include <time.h>
    46 
    47 #include <asm/prctl.h>
    48 #include <sys/ioctl.h>
    49 #include <sys/mman.h>
    50 #include <sys/prctl.h>
    51 #include <sys/types.h>
    52 #include <sys/stat.h>
    53 #include <linux/futex.h>
    54 #include <linux/filter.h>
    55 #include <linux/seccomp.h>
    56 #include <fcntl.h>
    57 #include <sched.h>
    58 #include <seccomp.h>
    59 #include <unistd.h>
    60 
    61 #include <attribute.h>
    62 
    63 #ifndef ARCH_CET_STATUS
    64 #define ARCH_CET_STATUS 0x3001
    65 #endif
    66 
    67 static ATTRIBUTE_FORMAT_PRINTF (2, 3) _Noreturn void
    68 fail (int error, const char *format, ...)
    69 {
    70   va_list ap;
    71   va_start (ap, format);
    72   vfprintf (stderr, format, ap);
    73   va_end (ap);
    74   if (error == 0)
    75     fputc ('\n', stderr);
    76   else
    77     {
    78       fputs (": ", stderr);
    79       errno = error;
    80       perror (NULL);
    81     }
    82   fflush (NULL);
    83   exit (EXIT_FAILURE);
    84 }
    85 
    86 /* This binary is trivial, so we use a single global filter context
    87    object that we release using `atexit'.  */
    88 
    89 static scmp_filter_ctx ctx;
    90 
    91 static void
    92 release_context (void)
    93 {
    94   seccomp_release (ctx);
    95 }
    96 
    97 /* Wrapper functions and macros for libseccomp functions.  We exit
    98    immediately upon any error to avoid error checking noise.  */
    99 
   100 static void
   101 set_attribute (enum scmp_filter_attr attr, uint32_t value)
   102 {
   103   int status = seccomp_attr_set (ctx, attr, value);
   104   if (status < 0)
   105     fail (-status, "seccomp_attr_set (ctx, %u, %u)", attr, value);
   106 }
   107 
   108 /* Like `seccomp_rule_add (ACTION, SYSCALL, ...)', except that you
   109    don't have to specify the number of comparator arguments, and any
   110    failure will exit the process.  */
   111 
   112 #define RULE(action, syscall, ...)                                   \
   113   do                                                                 \
   114     {                                                                \
   115       const struct scmp_arg_cmp arg_array[] = {__VA_ARGS__};         \
   116       enum { arg_cnt = sizeof arg_array / sizeof *arg_array };       \
   117       int status = seccomp_rule_add_array (ctx, (action), (syscall), \
   118                                            arg_cnt, arg_array);      \
   119       if (status < 0)                                                \
   120         fail (-status, "seccomp_rule_add_array (%s, %s, %d, {%s})",  \
   121               #action, #syscall, arg_cnt, #__VA_ARGS__);             \
   122     }                                                                \
   123   while (false)
   124 
   125 static void
   126 export_filter (const char *file,
   127                int (*function) (const scmp_filter_ctx, int),
   128                const char *name)
   129 {
   130   int fd;
   131   do
   132     fd = open (file,
   133                O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC,
   134                0644);
   135   while (fd < 0 && errno == EINTR);
   136   if (fd < 0)
   137     fail (errno, "open %s", file);
   138   int status = function (ctx, fd);
   139   if (status < 0)
   140     fail (-status, "%s", name);
   141   if (close (fd) != 0)
   142     fail (errno, "close");
   143 }
   144 
   145 #define EXPORT_FILTER(file, function) \
   146   export_filter ((file), (function), #function)
   147 
   148 int
   149 main (int argc, char **argv)
   150 {
   151   if (argc != 5)
   152     fail (0, "usage: %s out.bpf out.pfc out-exec.bpf out-exec.pfc",
   153           argv[0]);
   154 
   155   /* Any unhandled syscall should abort the Emacs process.  */
   156   ctx = seccomp_init (SCMP_ACT_KILL_PROCESS);
   157   if (ctx == NULL)
   158     fail (0, "seccomp_init");
   159   atexit (release_context);
   160 
   161   /* We want to abort immediately if the architecture is unknown.  */
   162   set_attribute (SCMP_FLTATR_ACT_BADARCH, SCMP_ACT_KILL_PROCESS);
   163   set_attribute (SCMP_FLTATR_CTL_NNP, 1);
   164   set_attribute (SCMP_FLTATR_CTL_TSYNC, 1);
   165 
   166   static_assert (CHAR_BIT == 8);
   167   static_assert (sizeof (int) == 4 && INT_MIN == INT32_MIN
   168                  && INT_MAX == INT32_MAX);
   169   static_assert (sizeof (long) == 8 && LONG_MIN == INT64_MIN
   170                  && LONG_MAX == INT64_MAX);
   171   static_assert (sizeof (void *) == 8);
   172   assert ((uintptr_t) NULL == 0);
   173 
   174   /* Allow a clean exit.  */
   175   RULE (SCMP_ACT_ALLOW, SCMP_SYS (exit));
   176   RULE (SCMP_ACT_ALLOW, SCMP_SYS (exit_group));
   177 
   178   /* Allow `mmap' and friends.  This is necessary for dynamic loading,
   179      reading the portable dump file, and thread creation.  We don't
   180      allow pages to be both writable and executable.  */
   181   static_assert (MAP_PRIVATE != 0);
   182   static_assert (MAP_SHARED != 0);
   183   RULE (SCMP_ACT_ALLOW, SCMP_SYS (mmap),
   184         SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
   185                     ~(PROT_NONE | PROT_READ | PROT_WRITE)),
   186         /* Only support known flags.  MAP_DENYWRITE is ignored, but
   187            some versions of the dynamic loader still use it.  Also
   188            allow allocating thread stacks.  */
   189         SCMP_A3_32 (SCMP_CMP_MASKED_EQ,
   190                     ~(MAP_SHARED | MAP_PRIVATE | MAP_FILE
   191                       | MAP_ANONYMOUS | MAP_FIXED | MAP_DENYWRITE
   192                       | MAP_STACK | MAP_NORESERVE),
   193                     0));
   194   RULE (SCMP_ACT_ALLOW, SCMP_SYS (mmap),
   195         SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
   196                     ~(PROT_NONE | PROT_READ | PROT_EXEC)),
   197         /* Only support known flags.  MAP_DENYWRITE is ignored, but
   198            some versions of the dynamic loader still use it. */
   199         SCMP_A3_32 (SCMP_CMP_MASKED_EQ,
   200                     ~(MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
   201                       | MAP_DENYWRITE),
   202                     0));
   203   RULE (SCMP_ACT_ALLOW, SCMP_SYS (munmap));
   204   RULE (SCMP_ACT_ALLOW, SCMP_SYS (mprotect),
   205         /* Don't allow making pages executable.  */
   206         SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
   207                     ~(PROT_NONE | PROT_READ | PROT_WRITE), 0));
   208 
   209   /* Allow restartable sequences.  The dynamic linker uses them.  */
   210   RULE (SCMP_ACT_ALLOW, SCMP_SYS (rseq));
   211 
   212   /* Futexes are used everywhere.  */
   213   RULE (SCMP_ACT_ALLOW, SCMP_SYS (futex),
   214         SCMP_A1_32 (SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE));
   215 
   216   /* Allow basic dynamic memory management.  */
   217   RULE (SCMP_ACT_ALLOW, SCMP_SYS (brk));
   218 
   219   /* Allow some status inquiries.  */
   220   RULE (SCMP_ACT_ALLOW, SCMP_SYS (uname));
   221   RULE (SCMP_ACT_ALLOW, SCMP_SYS (getuid));
   222   RULE (SCMP_ACT_ALLOW, SCMP_SYS (geteuid));
   223   RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpid));
   224   RULE (SCMP_ACT_ALLOW, SCMP_SYS (gettid));
   225   RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpgrp));
   226 
   227   /* Allow operations on open file descriptors.  File descriptors are
   228      capabilities, and operating on them shouldn't cause security
   229      issues.  */
   230   RULE (SCMP_ACT_ALLOW, SCMP_SYS (read));
   231   RULE (SCMP_ACT_ALLOW, SCMP_SYS (pread64));
   232   RULE (SCMP_ACT_ALLOW, SCMP_SYS (write));
   233   RULE (SCMP_ACT_ALLOW, SCMP_SYS (close));
   234   RULE (SCMP_ACT_ALLOW, SCMP_SYS (lseek));
   235   RULE (SCMP_ACT_ALLOW, SCMP_SYS (dup));
   236   RULE (SCMP_ACT_ALLOW, SCMP_SYS (dup2));
   237   RULE (SCMP_ACT_ALLOW, SCMP_SYS (fstat));
   238 
   239   /* Allow read operations on the filesystem.  If necessary, these
   240      should be further restricted using mount namespaces.  */
   241   RULE (SCMP_ACT_ALLOW, SCMP_SYS (access));
   242   RULE (SCMP_ACT_ALLOW, SCMP_SYS (faccessat));
   243 #ifdef __NR_faccessat2
   244   RULE (SCMP_ACT_ALLOW, SCMP_SYS (faccessat2));
   245 #endif
   246   RULE (SCMP_ACT_ALLOW, SCMP_SYS (stat));
   247   RULE (SCMP_ACT_ALLOW, SCMP_SYS (stat64));
   248   RULE (SCMP_ACT_ALLOW, SCMP_SYS (lstat));
   249   RULE (SCMP_ACT_ALLOW, SCMP_SYS (lstat64));
   250   RULE (SCMP_ACT_ALLOW, SCMP_SYS (fstatat64));
   251   RULE (SCMP_ACT_ALLOW, SCMP_SYS (newfstatat));
   252   RULE (SCMP_ACT_ALLOW, SCMP_SYS (readlink));
   253   RULE (SCMP_ACT_ALLOW, SCMP_SYS (readlinkat));
   254   RULE (SCMP_ACT_ALLOW, SCMP_SYS (getcwd));
   255 
   256   /* Allow opening files, assuming they are only opened for
   257      reading.  */
   258   static_assert (O_WRONLY != 0);
   259   static_assert (O_RDWR != 0);
   260   static_assert (O_CREAT != 0);
   261   RULE (SCMP_ACT_ALLOW, SCMP_SYS (open),
   262         SCMP_A1_32 (SCMP_CMP_MASKED_EQ,
   263                     ~(O_RDONLY | O_BINARY | O_CLOEXEC | O_PATH
   264                       | O_DIRECTORY | O_NOFOLLOW),
   265                     0));
   266   RULE (SCMP_ACT_ALLOW, SCMP_SYS (openat),
   267         SCMP_A2_32 (SCMP_CMP_MASKED_EQ,
   268                     ~(O_RDONLY | O_BINARY | O_CLOEXEC | O_PATH
   269                       | O_DIRECTORY | O_NOFOLLOW),
   270                     0));
   271 
   272   /* Allow `tcgetpgrp'.  */
   273   RULE (SCMP_ACT_ALLOW, SCMP_SYS (ioctl),
   274         SCMP_A0_32 (SCMP_CMP_EQ, STDIN_FILENO),
   275         SCMP_A1_32 (SCMP_CMP_EQ, TIOCGPGRP));
   276 
   277   /* Allow reading (but not setting) file flags.  */
   278   RULE (SCMP_ACT_ALLOW, SCMP_SYS (fcntl),
   279         SCMP_A1_32 (SCMP_CMP_EQ, F_GETFL));
   280   RULE (SCMP_ACT_ALLOW, SCMP_SYS (fcntl64),
   281         SCMP_A1_32 (SCMP_CMP_EQ, F_GETFL));
   282 
   283   /* Allow reading random numbers from the kernel.  */
   284   RULE (SCMP_ACT_ALLOW, SCMP_SYS (getrandom));
   285 
   286   /* Changing the umask is uncritical.  */
   287   RULE (SCMP_ACT_ALLOW, SCMP_SYS (umask));
   288 
   289   /* Allow creation of pipes.  */
   290   RULE (SCMP_ACT_ALLOW, SCMP_SYS (pipe));
   291   RULE (SCMP_ACT_ALLOW, SCMP_SYS (pipe2));
   292 
   293   /* Allow reading (but not changing) resource limits.  */
   294   RULE (SCMP_ACT_ALLOW, SCMP_SYS (getrlimit));
   295   RULE (SCMP_ACT_ALLOW, SCMP_SYS (prlimit64),
   296         SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */,
   297         SCMP_A2_64 (SCMP_CMP_EQ, 0) /* new_limit == NULL */);
   298 
   299   /* Block changing resource limits, but don't crash.  */
   300   RULE (SCMP_ACT_ERRNO (EPERM), SCMP_SYS (prlimit64),
   301         SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */,
   302         SCMP_A2_64 (SCMP_CMP_NE, 0) /* new_limit != NULL */);
   303 
   304   /* Emacs installs signal handlers, which is harmless.  */
   305   RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigaction));
   306   RULE (SCMP_ACT_ALLOW, SCMP_SYS (rt_sigaction));
   307   RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigprocmask));
   308   RULE (SCMP_ACT_ALLOW, SCMP_SYS (rt_sigprocmask));
   309 
   310   /* Allow reading the current time.  */
   311   RULE (SCMP_ACT_ALLOW, SCMP_SYS (clock_gettime),
   312         SCMP_A0_32 (SCMP_CMP_EQ, CLOCK_REALTIME));
   313   RULE (SCMP_ACT_ALLOW, SCMP_SYS (time));
   314   RULE (SCMP_ACT_ALLOW, SCMP_SYS (gettimeofday));
   315 
   316   /* Allow timer support.  */
   317   RULE (SCMP_ACT_ALLOW, SCMP_SYS (timer_create));
   318   RULE (SCMP_ACT_ALLOW, SCMP_SYS (timerfd_create));
   319 
   320   /* Allow thread creation.  See the NOTES section in the manual page
   321      for the `clone' function.  */
   322   RULE (SCMP_ACT_ALLOW, SCMP_SYS (clone),
   323         SCMP_A0_64 (SCMP_CMP_MASKED_EQ,
   324                     /* Flags needed to create threads.  See
   325                        create_thread in libc.  */
   326                     ~(CLONE_VM | CLONE_FS | CLONE_FILES
   327                       | CLONE_SYSVSEM | CLONE_SIGHAND | CLONE_THREAD
   328                       | CLONE_SETTLS | CLONE_PARENT_SETTID
   329                       | CLONE_CHILD_CLEARTID),
   330                     0));
   331   /* glibc 2.34+ pthread_create uses clone3.  */
   332   RULE (SCMP_ACT_ALLOW, SCMP_SYS (clone3));
   333   RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigaltstack));
   334   RULE (SCMP_ACT_ALLOW, SCMP_SYS (set_robust_list));
   335 
   336   /* Allow setting the process name for new threads.  */
   337   RULE (SCMP_ACT_ALLOW, SCMP_SYS (prctl),
   338         SCMP_A0_32 (SCMP_CMP_EQ, PR_SET_NAME));
   339 
   340   /* Allow some event handling functions used by glib.  */
   341   RULE (SCMP_ACT_ALLOW, SCMP_SYS (eventfd));
   342   RULE (SCMP_ACT_ALLOW, SCMP_SYS (eventfd2));
   343   RULE (SCMP_ACT_ALLOW, SCMP_SYS (wait4));
   344   RULE (SCMP_ACT_ALLOW, SCMP_SYS (poll));
   345   RULE (SCMP_ACT_ALLOW, SCMP_SYS (pidfd_open),
   346         SCMP_A1_32 (SCMP_CMP_EQ, 0));
   347 
   348   /* Don't allow creating sockets (network access would be extremely
   349      dangerous), but also don't crash.  */
   350   RULE (SCMP_ACT_ERRNO (EACCES), SCMP_SYS (socket));
   351 
   352   EXPORT_FILTER (argv[1], seccomp_export_bpf);
   353   EXPORT_FILTER (argv[2], seccomp_export_pfc);
   354 
   355   /* When applying a Seccomp filter before executing the Emacs binary
   356      (e.g. using the `bwrap' program), we need to allow further system
   357      calls.  Firstly, the wrapper binary will need to `execve' the
   358      Emacs binary.  Furthermore, the C library requires some system
   359      calls at startup time to set up thread-local storage.  */
   360   RULE (SCMP_ACT_ALLOW, SCMP_SYS (execve));
   361   RULE (SCMP_ACT_ALLOW, SCMP_SYS (set_tid_address));
   362   RULE (SCMP_ACT_ERRNO (EINVAL), SCMP_SYS (prctl),
   363         SCMP_A0_32 (SCMP_CMP_EQ, PR_CAPBSET_READ));
   364   RULE (SCMP_ACT_ALLOW, SCMP_SYS (arch_prctl),
   365         SCMP_A0_32 (SCMP_CMP_EQ, ARCH_SET_FS));
   366   RULE (SCMP_ACT_ERRNO (EINVAL), SCMP_SYS (arch_prctl),
   367         SCMP_A0_32 (SCMP_CMP_EQ, ARCH_CET_STATUS));
   368   RULE (SCMP_ACT_ALLOW, SCMP_SYS (statfs));
   369 
   370   /* We want to allow starting the Emacs binary itself with the
   371      --seccomp flag, so we need to allow the `prctl' and `seccomp'
   372      system calls.  */
   373   RULE (SCMP_ACT_ALLOW, SCMP_SYS (prctl),
   374         SCMP_A0_32 (SCMP_CMP_EQ, PR_SET_NO_NEW_PRIVS),
   375         SCMP_A1_64 (SCMP_CMP_EQ, 1), SCMP_A2_64 (SCMP_CMP_EQ, 0),
   376         SCMP_A3_64 (SCMP_CMP_EQ, 0), SCMP_A4_64 (SCMP_CMP_EQ, 0));
   377   RULE (SCMP_ACT_ALLOW, SCMP_SYS (seccomp),
   378         SCMP_A0_32 (SCMP_CMP_EQ, SECCOMP_SET_MODE_FILTER),
   379         SCMP_A1_32 (SCMP_CMP_EQ, SECCOMP_FILTER_FLAG_TSYNC));
   380 
   381   EXPORT_FILTER (argv[3], seccomp_export_bpf);
   382   EXPORT_FILTER (argv[4], seccomp_export_pfc);
   383 }

/* [<][>][^][v][top][bottom][index][help] */