github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/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 (!sc_security_tag_validate(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 }