github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/cmd/libsnap-confine-private/mountinfo-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 "mountinfo.h" 19 #include "mountinfo.c" 20 21 #include <glib.h> 22 23 static void test_parse_mountinfo_entry__sysfs(void) 24 { 25 const char *line = 26 "19 25 0:18 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw"; 27 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 28 g_assert_nonnull(entry); 29 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 30 g_assert_cmpint(entry->mount_id, ==, 19); 31 g_assert_cmpint(entry->parent_id, ==, 25); 32 g_assert_cmpint(entry->dev_major, ==, 0); 33 g_assert_cmpint(entry->dev_minor, ==, 18); 34 g_assert_cmpstr(entry->root, ==, "/"); 35 g_assert_cmpstr(entry->mount_dir, ==, "/sys"); 36 g_assert_cmpstr(entry->mount_opts, ==, 37 "rw,nosuid,nodev,noexec,relatime"); 38 g_assert_cmpstr(entry->optional_fields, ==, "shared:7"); 39 g_assert_cmpstr(entry->fs_type, ==, "sysfs"); 40 g_assert_cmpstr(entry->mount_source, ==, "sysfs"); 41 g_assert_cmpstr(entry->super_opts, ==, "rw"); 42 g_assert_null(entry->next); 43 } 44 45 // Parse the /run/snapd/ns bind mount (over itself) 46 // Note that /run is itself a tmpfs mount point. 47 static void test_parse_mountinfo_entry__snapd_ns(void) 48 { 49 const char *line = 50 "104 23 0:19 /snapd/ns /run/snapd/ns rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=99840k,mode=755"; 51 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 52 g_assert_nonnull(entry); 53 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 54 g_assert_cmpint(entry->mount_id, ==, 104); 55 g_assert_cmpint(entry->parent_id, ==, 23); 56 g_assert_cmpint(entry->dev_major, ==, 0); 57 g_assert_cmpint(entry->dev_minor, ==, 19); 58 g_assert_cmpstr(entry->root, ==, "/snapd/ns"); 59 g_assert_cmpstr(entry->mount_dir, ==, "/run/snapd/ns"); 60 g_assert_cmpstr(entry->mount_opts, ==, "rw,nosuid,noexec,relatime"); 61 g_assert_cmpstr(entry->optional_fields, ==, ""); 62 g_assert_cmpstr(entry->fs_type, ==, "tmpfs"); 63 g_assert_cmpstr(entry->mount_source, ==, "tmpfs"); 64 g_assert_cmpstr(entry->super_opts, ==, "rw,size=99840k,mode=755"); 65 g_assert_null(entry->next); 66 } 67 68 static void test_parse_mountinfo_entry__snapd_mnt(void) 69 { 70 const char *line = 71 "256 104 0:3 mnt:[4026532509] /run/snapd/ns/hello-world.mnt rw - nsfs nsfs rw"; 72 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 73 g_assert_nonnull(entry); 74 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 75 g_assert_cmpint(entry->mount_id, ==, 256); 76 g_assert_cmpint(entry->parent_id, ==, 104); 77 g_assert_cmpint(entry->dev_major, ==, 0); 78 g_assert_cmpint(entry->dev_minor, ==, 3); 79 g_assert_cmpstr(entry->root, ==, "mnt:[4026532509]"); 80 g_assert_cmpstr(entry->mount_dir, ==, "/run/snapd/ns/hello-world.mnt"); 81 g_assert_cmpstr(entry->mount_opts, ==, "rw"); 82 g_assert_cmpstr(entry->optional_fields, ==, ""); 83 g_assert_cmpstr(entry->fs_type, ==, "nsfs"); 84 g_assert_cmpstr(entry->mount_source, ==, "nsfs"); 85 g_assert_cmpstr(entry->super_opts, ==, "rw"); 86 g_assert_null(entry->next); 87 } 88 89 static void test_parse_mountinfo_entry__garbage(void) 90 { 91 const char *line = "256 104 0:3"; 92 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 93 g_assert_null(entry); 94 } 95 96 static void test_parse_mountinfo_entry__no_tags(void) 97 { 98 const char *line = 99 "1 2 3:4 root mount-dir mount-opts - fs-type mount-source super-opts"; 100 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 101 g_assert_nonnull(entry); 102 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 103 g_assert_cmpint(entry->mount_id, ==, 1); 104 g_assert_cmpint(entry->parent_id, ==, 2); 105 g_assert_cmpint(entry->dev_major, ==, 3); 106 g_assert_cmpint(entry->dev_minor, ==, 4); 107 g_assert_cmpstr(entry->root, ==, "root"); 108 g_assert_cmpstr(entry->mount_dir, ==, "mount-dir"); 109 g_assert_cmpstr(entry->mount_opts, ==, "mount-opts"); 110 g_assert_cmpstr(entry->optional_fields, ==, ""); 111 g_assert_cmpstr(entry->fs_type, ==, "fs-type"); 112 g_assert_cmpstr(entry->mount_source, ==, "mount-source"); 113 g_assert_cmpstr(entry->super_opts, ==, "super-opts"); 114 g_assert_null(entry->next); 115 } 116 117 static void test_parse_mountinfo_entry__one_tag(void) 118 { 119 const char *line = 120 "1 2 3:4 root mount-dir mount-opts tag:1 - fs-type mount-source super-opts"; 121 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 122 g_assert_nonnull(entry); 123 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 124 g_assert_cmpint(entry->mount_id, ==, 1); 125 g_assert_cmpint(entry->parent_id, ==, 2); 126 g_assert_cmpint(entry->dev_major, ==, 3); 127 g_assert_cmpint(entry->dev_minor, ==, 4); 128 g_assert_cmpstr(entry->root, ==, "root"); 129 g_assert_cmpstr(entry->mount_dir, ==, "mount-dir"); 130 g_assert_cmpstr(entry->mount_opts, ==, "mount-opts"); 131 g_assert_cmpstr(entry->optional_fields, ==, "tag:1"); 132 g_assert_cmpstr(entry->fs_type, ==, "fs-type"); 133 g_assert_cmpstr(entry->mount_source, ==, "mount-source"); 134 g_assert_cmpstr(entry->super_opts, ==, "super-opts"); 135 g_assert_null(entry->next); 136 } 137 138 static void test_parse_mountinfo_entry__many_tags(void) 139 { 140 const char *line = 141 "1 2 3:4 root mount-dir mount-opts tag:1 tag:2 tag:3 tag:4 - fs-type mount-source super-opts"; 142 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 143 g_assert_nonnull(entry); 144 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 145 g_assert_cmpint(entry->mount_id, ==, 1); 146 g_assert_cmpint(entry->parent_id, ==, 2); 147 g_assert_cmpint(entry->dev_major, ==, 3); 148 g_assert_cmpint(entry->dev_minor, ==, 4); 149 g_assert_cmpstr(entry->root, ==, "root"); 150 g_assert_cmpstr(entry->mount_dir, ==, "mount-dir"); 151 g_assert_cmpstr(entry->mount_opts, ==, "mount-opts"); 152 g_assert_cmpstr(entry->optional_fields, ==, "tag:1 tag:2 tag:3 tag:4"); 153 g_assert_cmpstr(entry->fs_type, ==, "fs-type"); 154 g_assert_cmpstr(entry->mount_source, ==, "mount-source"); 155 g_assert_cmpstr(entry->super_opts, ==, "super-opts"); 156 g_assert_null(entry->next); 157 } 158 159 static void test_parse_mountinfo_entry__empty_source(void) 160 { 161 const char *line = 162 "304 301 0:45 / /snap/test-snapd-content-advanced-plug/x1 rw,relatime - tmpfs rw"; 163 sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 164 g_assert_nonnull(entry); 165 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 166 g_assert_cmpint(entry->mount_id, ==, 304); 167 g_assert_cmpint(entry->parent_id, ==, 301); 168 g_assert_cmpint(entry->dev_major, ==, 0); 169 g_assert_cmpint(entry->dev_minor, ==, 45); 170 g_assert_cmpstr(entry->root, ==, "/"); 171 g_assert_cmpstr(entry->mount_dir, ==, 172 "/snap/test-snapd-content-advanced-plug/x1"); 173 g_assert_cmpstr(entry->mount_opts, ==, "rw,relatime"); 174 g_assert_cmpstr(entry->optional_fields, ==, ""); 175 g_assert_cmpstr(entry->fs_type, ==, "tmpfs"); 176 g_assert_cmpstr(entry->mount_source, ==, ""); 177 g_assert_cmpstr(entry->super_opts, ==, "rw"); 178 g_assert_null(entry->next); 179 } 180 181 static void test_parse_mountinfo_entry__octal_escaping(void) 182 { 183 const char *line; 184 struct sc_mountinfo_entry *entry; 185 186 // The kernel escapes spaces as \040 187 line = "2 1 0:54 / /tmp rw - tmpfs tricky\\040path rw"; 188 entry = sc_parse_mountinfo_entry(line); 189 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 190 g_assert_nonnull(entry); 191 g_assert_cmpstr(entry->mount_source, ==, "tricky path"); 192 193 // kernel escapes newlines as \012 194 line = "2 1 0:54 / /tmp rw - tmpfs tricky\\012path rw"; 195 entry = sc_parse_mountinfo_entry(line); 196 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 197 g_assert_nonnull(entry); 198 g_assert_cmpstr(entry->mount_source, ==, "tricky\npath"); 199 200 // kernel escapes tabs as \011 201 line = "2 1 0:54 / /tmp rw - tmpfs tricky\\011path rw"; 202 entry = sc_parse_mountinfo_entry(line); 203 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 204 g_assert_nonnull(entry); 205 g_assert_cmpstr(entry->mount_source, ==, "tricky\tpath"); 206 207 // kernel escapes forward slashes as \057 208 line = "2 1 0:54 / /tmp rw - tmpfs tricky\\057path rw"; 209 entry = sc_parse_mountinfo_entry(line); 210 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 211 g_assert_nonnull(entry); 212 g_assert_cmpstr(entry->mount_source, ==, "tricky/path"); 213 } 214 215 static void test_parse_mountinfo_entry__broken_octal_escaping(void) 216 { 217 // Invalid octal escape sequences are left intact. 218 const char *line = 219 "2074 27 0:54 / /tmp/strange-dir rw,relatime shared:1039 - tmpfs no\\888thing rw\\"; 220 struct sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 221 g_assert_nonnull(entry); 222 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 223 g_assert_cmpint(entry->mount_id, ==, 2074); 224 g_assert_cmpint(entry->parent_id, ==, 27); 225 g_assert_cmpint(entry->dev_major, ==, 0); 226 g_assert_cmpint(entry->dev_minor, ==, 54); 227 g_assert_cmpstr(entry->root, ==, "/"); 228 g_assert_cmpstr(entry->mount_dir, ==, "/tmp/strange-dir"); 229 g_assert_cmpstr(entry->mount_opts, ==, "rw,relatime"); 230 g_assert_cmpstr(entry->optional_fields, ==, "shared:1039"); 231 g_assert_cmpstr(entry->fs_type, ==, "tmpfs"); 232 g_assert_cmpstr(entry->mount_source, ==, "no\\888thing"); 233 g_assert_cmpstr(entry->super_opts, ==, "rw\\"); 234 g_assert_null(entry->next); 235 } 236 237 static void test_parse_mountinfo_entry__unescaped_whitespace(void) 238 { 239 // The kernel does not escape '\r' 240 const char *line = 241 "2074 27 0:54 / /tmp/strange\rdir rw,relatime shared:1039 - tmpfs tmpfs rw"; 242 struct sc_mountinfo_entry *entry = sc_parse_mountinfo_entry(line); 243 g_assert_nonnull(entry); 244 g_test_queue_destroy((GDestroyNotify) sc_free_mountinfo_entry, entry); 245 g_assert_cmpint(entry->mount_id, ==, 2074); 246 g_assert_cmpint(entry->parent_id, ==, 27); 247 g_assert_cmpint(entry->dev_major, ==, 0); 248 g_assert_cmpint(entry->dev_minor, ==, 54); 249 g_assert_cmpstr(entry->root, ==, "/"); 250 g_assert_cmpstr(entry->mount_dir, ==, "/tmp/strange\rdir"); 251 g_assert_cmpstr(entry->mount_opts, ==, "rw,relatime"); 252 g_assert_cmpstr(entry->optional_fields, ==, "shared:1039"); 253 g_assert_cmpstr(entry->fs_type, ==, "tmpfs"); 254 g_assert_cmpstr(entry->mount_source, ==, "tmpfs"); 255 g_assert_cmpstr(entry->super_opts, ==, "rw"); 256 g_assert_null(entry->next); 257 } 258 259 static void __attribute__((constructor)) init(void) 260 { 261 g_test_add_func("/mountinfo/parse_mountinfo_entry/sysfs", 262 test_parse_mountinfo_entry__sysfs); 263 g_test_add_func("/mountinfo/parse_mountinfo_entry/snapd-ns", 264 test_parse_mountinfo_entry__snapd_ns); 265 g_test_add_func("/mountinfo/parse_mountinfo_entry/snapd-mnt", 266 test_parse_mountinfo_entry__snapd_mnt); 267 g_test_add_func("/mountinfo/parse_mountinfo_entry/garbage", 268 test_parse_mountinfo_entry__garbage); 269 g_test_add_func("/mountinfo/parse_mountinfo_entry/no_tags", 270 test_parse_mountinfo_entry__no_tags); 271 g_test_add_func("/mountinfo/parse_mountinfo_entry/one_tags", 272 test_parse_mountinfo_entry__one_tag); 273 g_test_add_func("/mountinfo/parse_mountinfo_entry/many_tags", 274 test_parse_mountinfo_entry__many_tags); 275 g_test_add_func 276 ("/mountinfo/parse_mountinfo_entry/empty_source", 277 test_parse_mountinfo_entry__empty_source); 278 g_test_add_func("/mountinfo/parse_mountinfo_entry/octal_escaping", 279 test_parse_mountinfo_entry__octal_escaping); 280 g_test_add_func 281 ("/mountinfo/parse_mountinfo_entry/broken_octal_escaping", 282 test_parse_mountinfo_entry__broken_octal_escaping); 283 g_test_add_func("/mountinfo/parse_mountinfo_entry/unescaped_whitespace", 284 test_parse_mountinfo_entry__unescaped_whitespace); 285 }