github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/snap-confine/snap-confine-invocation.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  #include "snap-confine-invocation.h"
    18  
    19  #include <stdlib.h>
    20  #include <string.h>
    21  #include <unistd.h>
    22  
    23  #include "../libsnap-confine-private/cleanup-funcs.h"
    24  #include "../libsnap-confine-private/snap.h"
    25  #include "../libsnap-confine-private/string-utils.h"
    26  #include "../libsnap-confine-private/utils.h"
    27  
    28  void sc_init_invocation(sc_invocation *inv, const struct sc_args *args, const char *snap_instance) {
    29      /* Snap instance name is conveyed via untrusted environment. It may be
    30       * unset (typically when experimenting with snap-confine by hand). It
    31       * must also be a valid snap instance name. */
    32      if (snap_instance == NULL) {
    33          die("cannot use NULL snap instance name");
    34      }
    35      sc_instance_name_validate(snap_instance, NULL);
    36  
    37      /* The security tag is conveyed via untrusted command line. It must be
    38       * in agreement with snap instance name and must be a valid security
    39       * tag. */
    40      const char *security_tag = sc_args_security_tag(args);
    41      if (!verify_security_tag(security_tag, snap_instance)) {
    42          die("security tag %s not allowed", security_tag);
    43      }
    44  
    45      /* The base snap name is conveyed via untrusted, optional, command line
    46       * argument. It may be omitted where it implies the "core" snap is the
    47       * base. */
    48      const char *base_snap_name = sc_args_base_snap(args);
    49      if (base_snap_name == NULL) {
    50          base_snap_name = "core";
    51      }
    52      sc_snap_name_validate(base_snap_name, NULL);
    53  
    54      /* The executable is conveyed via untrusted command line. It must be set
    55       * but cannot be validated further than that at this time. It might be
    56       * arguable to validate it to be snap-exec in one of the well-known
    57       * locations or one of the special-cases like strace / gdb but this is
    58       * not done at this time. */
    59      const char *executable = sc_args_executable(args);
    60      if (executable == NULL) {
    61          die("cannot run with NULL executable");
    62      }
    63  
    64      /* Instance name length + NULL termination */
    65      char snap_name[SNAP_NAME_LEN + 1] = {0};
    66      sc_snap_drop_instance_key(snap_instance, snap_name, sizeof snap_name);
    67  
    68      /* Invocation helps to pass relevant data to various parts of snap-confine. */
    69      memset(inv, 0, sizeof *inv);
    70      inv->base_snap_name = sc_strdup(base_snap_name);
    71      inv->orig_base_snap_name = sc_strdup(base_snap_name);
    72      inv->executable = sc_strdup(executable);
    73      inv->security_tag = sc_strdup(security_tag);
    74      inv->snap_instance = sc_strdup(snap_instance);
    75      inv->snap_name = sc_strdup(snap_name);
    76      inv->classic_confinement = sc_args_is_classic_confinement(args);
    77  
    78      // construct rootfs_dir based on base_snap_name
    79      char mount_point[PATH_MAX] = {0};
    80      sc_must_snprintf(mount_point, sizeof mount_point, "%s/%s/current", SNAP_MOUNT_DIR, inv->base_snap_name);
    81      inv->rootfs_dir = sc_strdup(mount_point);
    82  
    83      debug("security tag: %s", inv->security_tag);
    84      debug("executable:   %s", inv->executable);
    85      debug("confinement:  %s", inv->classic_confinement ? "classic" : "non-classic");
    86      debug("base snap:    %s", inv->base_snap_name);
    87  }
    88  
    89  void sc_cleanup_invocation(sc_invocation *inv) {
    90      if (inv != NULL) {
    91          sc_cleanup_string(&inv->snap_instance);
    92          sc_cleanup_string(&inv->snap_name);
    93          sc_cleanup_string(&inv->base_snap_name);
    94          sc_cleanup_string(&inv->orig_base_snap_name);
    95          sc_cleanup_string(&inv->security_tag);
    96          sc_cleanup_string(&inv->executable);
    97          sc_cleanup_string(&inv->rootfs_dir);
    98      }
    99  }
   100  
   101  void sc_check_rootfs_dir(sc_invocation *inv) {
   102      if (access(inv->rootfs_dir, F_OK) == 0) {
   103          return;
   104      }
   105  
   106      /* As a special fallback, allow the base snap to degrade from "core" to
   107       * "ubuntu-core". This is needed for the migration from old
   108       * ubuntu-core based systems to the new core.
   109       */
   110      if (sc_streq(inv->base_snap_name, "core")) {
   111          char mount_point[PATH_MAX] = {0};
   112  
   113          /* For "core" we can still use the ubuntu-core snap. This is helpful in
   114           * the migration path when new snap-confine runs before snapd has
   115           * finished obtaining the core snap. */
   116          sc_must_snprintf(mount_point, sizeof mount_point, "%s/%s/current", SNAP_MOUNT_DIR, "ubuntu-core");
   117          if (access(mount_point, F_OK) == 0) {
   118              sc_cleanup_string(&inv->base_snap_name);
   119              inv->base_snap_name = sc_strdup("ubuntu-core");
   120              sc_cleanup_string(&inv->rootfs_dir);
   121              inv->rootfs_dir = sc_strdup(mount_point);
   122              debug("falling back to ubuntu-core instead of unavailable core snap");
   123              return;
   124          }
   125      }
   126  
   127      if (sc_streq(inv->base_snap_name, "core16")) {
   128          char mount_point[PATH_MAX] = {0};
   129  
   130          /* For "core16" we can still use the "core" snap. This is useful
   131           * to help people transition to core16 bases without requiring
   132           * twice the disk space.
   133           */
   134          sc_must_snprintf(mount_point, sizeof mount_point, "%s/%s/current", SNAP_MOUNT_DIR, "core");
   135          if (access(mount_point, F_OK) == 0) {
   136              sc_cleanup_string(&inv->base_snap_name);
   137              inv->base_snap_name = sc_strdup("core");
   138              sc_cleanup_string(&inv->rootfs_dir);
   139              inv->rootfs_dir = sc_strdup(mount_point);
   140              debug("falling back to core instead of unavailable core16 snap");
   141              return;
   142          }
   143      }
   144  
   145      die("cannot locate base snap %s", inv->base_snap_name);
   146  }