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  }