github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/snap-confine/seccomp-support-ext.c (about)

     1  /*
     2   * Copyright (C) 2019 Canonical Ltd
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License version 3 as
     6   * published by the Free Software Foundation.
     7   *
     8   * This program is distributed in the hope that it will be useful,
     9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11   * GNU General Public License for more details.
    12   *
    13   * You should have received a copy of the GNU General Public License
    14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15   *
    16   */
    17  #ifdef HAVE_CONFIG_H
    18  #include "config.h"
    19  #endif
    20  
    21  #include "seccomp-support-ext.h"
    22  
    23  #include <errno.h>
    24  #include <linux/seccomp.h>
    25  #include <stdio.h>
    26  #include <sys/prctl.h>
    27  #include <sys/syscall.h>
    28  #include <sys/types.h>
    29  #include <unistd.h>
    30  
    31  #include "../libsnap-confine-private/utils.h"
    32  
    33  #ifndef SECCOMP_FILTER_FLAG_LOG
    34  #define SECCOMP_FILTER_FLAG_LOG 2
    35  #endif
    36  
    37  #ifndef seccomp
    38  // prototype because we build with -Wstrict-prototypes
    39  int seccomp(unsigned int operation, unsigned int flags, void *args);
    40  
    41  int seccomp(unsigned int operation, unsigned int flags, void *args) {
    42      errno = 0;
    43      return syscall(__NR_seccomp, operation, flags, args);
    44  }
    45  #endif
    46  
    47  size_t sc_read_seccomp_filter(const char *filename, char *buf, size_t buf_size) {
    48      if (buf_size == 0) {
    49          die("seccomp load buffer cannot be empty");
    50      }
    51      FILE *file = fopen(filename, "rb");
    52      if (file == NULL) {
    53          die("cannot open seccomp filter %s", filename);
    54      }
    55      size_t num_read = fread(buf, 1, buf_size - 1, file);
    56      buf[num_read] = '\0';
    57      if (ferror(file) != 0) {
    58          die("cannot read seccomp profile %s", filename);
    59      }
    60      if (feof(file) == 0) {
    61          die("cannot fit seccomp profile %s to memory buffer", filename);
    62      }
    63      fclose(file);
    64      debug("read %zu bytes from %s", num_read, filename);
    65      return num_read;
    66  }
    67  
    68  void sc_apply_seccomp_filter(struct sock_fprog *prog) {
    69      int err;
    70  
    71      // Load filter into the kernel (by this point we have dropped to the
    72      // calling user but still retain CAP_SYS_ADMIN).
    73      //
    74      // Importantly we are intentionally *not* setting NO_NEW_PRIVS because it
    75      // interferes with exec transitions in AppArmor with certain snapd
    76      // interfaces. Not setting NO_NEW_PRIVS does mean that applications can
    77      // adjust their sandbox if they have CAP_SYS_ADMIN or, if running on < 4.8
    78      // kernels, break out of the seccomp via ptrace. Both CAP_SYS_ADMIN and
    79      // 'ptrace (trace)' are blocked by AppArmor with typical snapd interfaces.
    80      err = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_LOG, prog);
    81      if (err != 0) {
    82          /* The profile may fail to load using the "modern" interface.
    83           * In such case use the older prctl-based interface instead. */
    84          switch (errno) {
    85              case ENOSYS:
    86                  debug("kernel doesn't support the seccomp(2) syscall");
    87                  break;
    88              case EINVAL:
    89                  debug("kernel may not support the SECCOMP_FILTER_FLAG_LOG flag");
    90                  break;
    91          }
    92          debug("falling back to prctl(2) syscall to load seccomp filter");
    93          err = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog);
    94          if (err != 0) {
    95              die("cannot apply seccomp profile");
    96          }
    97      }
    98  }