github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/snap-confine/ns-support-test.c (about) 1 /* 2 * Copyright (C) 2016 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 18 #include "ns-support.h" 19 #include "ns-support.c" 20 21 #include "../libsnap-confine-private/cleanup-funcs.h" 22 #include "../libsnap-confine-private/test-utils.h" 23 24 #include <errno.h> 25 #include <linux/magic.h> // for NSFS_MAGIC 26 #include <sys/utsname.h> 27 #include <sys/vfs.h> 28 29 #include <glib.h> 30 #include <glib/gstdio.h> 31 32 // Set alternate namespace directory 33 static void sc_set_ns_dir(const char *dir) 34 { 35 sc_ns_dir = dir; 36 } 37 38 // A variant of unsetenv that is compatible with GDestroyNotify 39 static void my_unsetenv(const char *k) 40 { 41 unsetenv(k); 42 } 43 44 // Use temporary directory for namespace groups. 45 // 46 // The directory is automatically reset to the real value at the end of the 47 // test. 48 static const char *sc_test_use_fake_ns_dir(void) 49 { 50 char *ns_dir = NULL; 51 if (g_test_subprocess()) { 52 // Check if the environment variable is set. If so then someone is already 53 // managing the temporary directory and we should not create a new one. 54 ns_dir = getenv("SNAP_CONFINE_NS_DIR"); 55 g_assert_nonnull(ns_dir); 56 } else { 57 ns_dir = g_dir_make_tmp(NULL, NULL); 58 g_assert_nonnull(ns_dir); 59 g_test_queue_free(ns_dir); 60 g_assert_cmpint(setenv("SNAP_CONFINE_NS_DIR", ns_dir, 0), ==, 61 0); 62 g_test_queue_destroy((GDestroyNotify) my_unsetenv, 63 "SNAP_CONFINE_NS_DIR"); 64 g_test_queue_destroy((GDestroyNotify) rm_rf_tmp, ns_dir); 65 } 66 g_test_queue_destroy((GDestroyNotify) sc_set_ns_dir, SC_NS_DIR); 67 sc_set_ns_dir(ns_dir); 68 return ns_dir; 69 } 70 71 // Check that allocating a namespace group sets up internal data structures to 72 // safe values. 73 static void test_sc_alloc_mount_ns(void) 74 { 75 struct sc_mount_ns *group = NULL; 76 group = sc_alloc_mount_ns(); 77 g_test_queue_free(group); 78 g_assert_nonnull(group); 79 g_assert_cmpint(group->dir_fd, ==, -1); 80 g_assert_cmpint(group->pipe_master[0], ==, -1); 81 g_assert_cmpint(group->pipe_master[1], ==, -1); 82 g_assert_cmpint(group->pipe_helper[0], ==, -1); 83 g_assert_cmpint(group->pipe_helper[1], ==, -1); 84 g_assert_cmpint(group->child, ==, 0); 85 g_assert_null(group->name); 86 } 87 88 // Initialize a namespace group. 89 // 90 // The group is automatically destroyed at the end of the test. 91 static struct sc_mount_ns *sc_test_open_mount_ns(const char *group_name) 92 { 93 // Initialize a namespace group 94 struct sc_mount_ns *group = NULL; 95 if (group_name == NULL) { 96 group_name = "test-group"; 97 } 98 group = sc_open_mount_ns(group_name); 99 g_test_queue_destroy((GDestroyNotify) sc_close_mount_ns, group); 100 // Check if the returned group data looks okay 101 g_assert_nonnull(group); 102 g_assert_cmpint(group->dir_fd, !=, -1); 103 g_assert_cmpint(group->pipe_master[0], ==, -1); 104 g_assert_cmpint(group->pipe_master[1], ==, -1); 105 g_assert_cmpint(group->pipe_helper[0], ==, -1); 106 g_assert_cmpint(group->pipe_helper[1], ==, -1); 107 g_assert_cmpint(group->child, ==, 0); 108 g_assert_cmpstr(group->name, ==, group_name); 109 return group; 110 } 111 112 // Check that initializing a namespace group creates the appropriate 113 // filesystem structure. 114 static void test_sc_open_mount_ns(void) 115 { 116 const char *ns_dir = sc_test_use_fake_ns_dir(); 117 sc_test_open_mount_ns(NULL); 118 // Check that the group directory exists 119 g_assert_true(g_file_test 120 (ns_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)); 121 } 122 123 // Sanity check, ensure that the namespace filesystem identifier is what we 124 // expect, aka NSFS_MAGIC. 125 static void test_nsfs_fs_id(void) 126 { 127 struct utsname uts; 128 if (uname(&uts) < 0) { 129 g_test_message("cannot use uname(2)"); 130 g_test_fail(); 131 return; 132 } 133 int major, minor; 134 if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { 135 g_test_message("cannot use sscanf(2) to parse kernel release"); 136 g_test_fail(); 137 return; 138 } 139 if (major < 3 || (major == 3 && minor < 19)) { 140 g_test_skip("this test needs kernel 3.19+"); 141 return; 142 } 143 struct statfs buf; 144 int err = statfs("/proc/self/ns/mnt", &buf); 145 g_assert_cmpint(err, ==, 0); 146 g_assert_cmpint(buf.f_type, ==, NSFS_MAGIC); 147 } 148 149 static void __attribute__((constructor)) init(void) 150 { 151 g_test_add_func("/ns/sc_alloc_mount_ns", test_sc_alloc_mount_ns); 152 g_test_add_func("/ns/sc_open_mount_ns", test_sc_open_mount_ns); 153 g_test_add_func("/ns/nsfs_fs_id", test_nsfs_fs_id); 154 }