github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/snap-confine/snap-confine-args-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 "snap-confine-args.h"
    19  #include "snap-confine-args.c"
    20  #include "../libsnap-confine-private/cleanup-funcs.h"
    21  
    22  #include <stdarg.h>
    23  
    24  #include <glib.h>
    25  
    26  static void test_sc_nonfatal_parse_args__typical(void)
    27  {
    28  	// Test that typical invocation of snap-confine is parsed correctly.
    29  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
    30  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
    31  
    32  	int argc;
    33  	char **argv;
    34  	test_argc_argv(&argc, &argv,
    35  		       "/usr/lib/snapd/snap-confine", "snap.SNAP_NAME.APP_NAME",
    36  		       "/usr/lib/snapd/snap-exec", "--option", "arg", NULL);
    37  
    38  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
    39  	g_assert_null(err);
    40  	g_assert_nonnull(args);
    41  
    42  	// Check supported switches and arguments
    43  	g_assert_cmpstr(sc_args_security_tag(args), ==,
    44  			"snap.SNAP_NAME.APP_NAME");
    45  	g_assert_cmpstr(sc_args_executable(args), ==,
    46  			"/usr/lib/snapd/snap-exec");
    47  	g_assert_cmpint(sc_args_is_version_query(args), ==, false);
    48  	g_assert_cmpint(sc_args_is_classic_confinement(args), ==, false);
    49  	g_assert_null(sc_args_base_snap(args));
    50  
    51  	// Check remaining arguments
    52  	g_assert_cmpint(argc, ==, 3);
    53  	g_assert_cmpstr(argv[0], ==, "/usr/lib/snapd/snap-confine");
    54  	g_assert_cmpstr(argv[1], ==, "--option");
    55  	g_assert_cmpstr(argv[2], ==, "arg");
    56  	g_assert_null(argv[3]);
    57  }
    58  
    59  static void test_sc_cleanup_args(void)
    60  {
    61  	// Check that NULL argument parser can be cleaned up
    62  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
    63  	struct sc_args *args = NULL;
    64  	sc_cleanup_args(&args);
    65  
    66  	// Check that a non-NULL argument parser can be cleaned up
    67  	int argc;
    68  	char **argv;
    69  	test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine",
    70  		       "snap.SNAP_NAME.APP_NAME", "/usr/lib/snapd/snap-exec",
    71  		       NULL);
    72  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
    73  	g_assert_null(err);
    74  	g_assert_nonnull(args);
    75  
    76  	sc_cleanup_args(&args);
    77  	g_assert_null(args);
    78  }
    79  
    80  static void test_sc_nonfatal_parse_args__typical_classic(void)
    81  {
    82  	// Test that typical invocation of snap-confine is parsed correctly.
    83  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
    84  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
    85  
    86  	int argc;
    87  	char **argv;
    88  	test_argc_argv(&argc, &argv,
    89  		       "/usr/lib/snapd/snap-confine", "--classic",
    90  		       "snap.SNAP_NAME.APP_NAME", "/usr/lib/snapd/snap-exec",
    91  		       "--option", "arg", NULL);
    92  
    93  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
    94  	g_assert_null(err);
    95  	g_assert_nonnull(args);
    96  
    97  	// Check supported switches and arguments
    98  	g_assert_cmpstr(sc_args_security_tag(args), ==,
    99  			"snap.SNAP_NAME.APP_NAME");
   100  	g_assert_cmpstr(sc_args_executable(args), ==,
   101  			"/usr/lib/snapd/snap-exec");
   102  	g_assert_cmpint(sc_args_is_version_query(args), ==, false);
   103  	g_assert_cmpint(sc_args_is_classic_confinement(args), ==, true);
   104  
   105  	// Check remaining arguments
   106  	g_assert_cmpint(argc, ==, 3);
   107  	g_assert_cmpstr(argv[0], ==, "/usr/lib/snapd/snap-confine");
   108  	g_assert_cmpstr(argv[1], ==, "--option");
   109  	g_assert_cmpstr(argv[2], ==, "arg");
   110  	g_assert_null(argv[3]);
   111  }
   112  
   113  static void test_sc_nonfatal_parse_args__ubuntu_core_launcher(void)
   114  {
   115  	// Test that typical legacy invocation of snap-confine via the
   116  	// ubuntu-core-launcher symlink, with duplicated security tag, is parsed
   117  	// correctly.
   118  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   119  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   120  
   121  	int argc;
   122  	char **argv;
   123  	test_argc_argv(&argc, &argv,
   124  		       "/usr/bin/ubuntu-core-launcher",
   125  		       "snap.SNAP_NAME.APP_NAME", "snap.SNAP_NAME.APP_NAME",
   126  		       "/usr/lib/snapd/snap-exec", "--option", "arg", NULL);
   127  
   128  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   129  	g_assert_null(err);
   130  	g_assert_nonnull(args);
   131  
   132  	// Check supported switches and arguments
   133  	g_assert_cmpstr(sc_args_security_tag(args), ==,
   134  			"snap.SNAP_NAME.APP_NAME");
   135  	g_assert_cmpstr(sc_args_executable(args), ==,
   136  			"/usr/lib/snapd/snap-exec");
   137  	g_assert_cmpint(sc_args_is_version_query(args), ==, false);
   138  	g_assert_cmpint(sc_args_is_classic_confinement(args), ==, false);
   139  
   140  	// Check remaining arguments
   141  	g_assert_cmpint(argc, ==, 3);
   142  	g_assert_cmpstr(argv[0], ==, "/usr/bin/ubuntu-core-launcher");
   143  	g_assert_cmpstr(argv[1], ==, "--option");
   144  	g_assert_cmpstr(argv[2], ==, "arg");
   145  	g_assert_null(argv[3]);
   146  }
   147  
   148  static void test_sc_nonfatal_parse_args__version(void)
   149  {
   150  	// Test that snap-confine --version is detected.
   151  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   152  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   153  
   154  	int argc;
   155  	char **argv;
   156  	test_argc_argv(&argc, &argv,
   157  		       "/usr/lib/snapd/snap-confine", "--version", "ignored",
   158  		       "garbage", NULL);
   159  
   160  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   161  	g_assert_null(err);
   162  	g_assert_nonnull(args);
   163  
   164  	// Check supported switches and arguments
   165  	g_assert_null(sc_args_security_tag(args));
   166  	g_assert_null(sc_args_executable(args));
   167  	g_assert_cmpint(sc_args_is_version_query(args), ==, true);
   168  	g_assert_cmpint(sc_args_is_classic_confinement(args), ==, false);
   169  
   170  	// Check remaining arguments
   171  	g_assert_cmpint(argc, ==, 3);
   172  	g_assert_cmpstr(argv[0], ==, "/usr/lib/snapd/snap-confine");
   173  	g_assert_cmpstr(argv[1], ==, "ignored");
   174  	g_assert_cmpstr(argv[2], ==, "garbage");
   175  	g_assert_null(argv[3]);
   176  }
   177  
   178  static void test_sc_nonfatal_parse_args__evil_input(void)
   179  {
   180  	// Check that calling without any arguments is reported as error.
   181  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   182  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   183  
   184  	// NULL argcp/argvp attack
   185  	args = sc_nonfatal_parse_args(NULL, NULL, &err);
   186  
   187  	g_assert_nonnull(err);
   188  	g_assert_null(args);
   189  	g_assert_cmpstr(sc_error_msg(err), ==,
   190  			"cannot parse arguments, argcp or argvp is NULL");
   191  	sc_cleanup_error(&err);
   192  
   193  	int argc;
   194  	char **argv;
   195  
   196  	// NULL argv attack
   197  	argc = 0;
   198  	argv = NULL;
   199  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   200  
   201  	g_assert_nonnull(err);
   202  	g_assert_null(args);
   203  	g_assert_cmpstr(sc_error_msg(err), ==,
   204  			"cannot parse arguments, argc is zero or argv is NULL");
   205  	sc_cleanup_error(&err);
   206  
   207  	// NULL argv[i] attack
   208  	test_argc_argv(&argc, &argv,
   209  		       "/usr/lib/snapd/snap-confine", "--version", "ignored",
   210  		       "garbage", NULL);
   211  	argv[1] = NULL;		// overwrite --version with NULL
   212  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   213  
   214  	g_assert_nonnull(err);
   215  	g_assert_null(args);
   216  	g_assert_cmpstr(sc_error_msg(err), ==,
   217  			"cannot parse arguments, argument at index 1 is NULL");
   218  }
   219  
   220  static void test_sc_nonfatal_parse_args__nothing_to_parse(void)
   221  {
   222  	// Check that calling without any arguments is reported as error.
   223  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   224  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   225  
   226  	int argc;
   227  	char **argv;
   228  	test_argc_argv(&argc, &argv, NULL);
   229  
   230  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   231  	g_assert_nonnull(err);
   232  	g_assert_null(args);
   233  
   234  	// Check the error that we've got
   235  	g_assert_cmpstr(sc_error_msg(err), ==,
   236  			"cannot parse arguments, argc is zero or argv is NULL");
   237  }
   238  
   239  static void test_sc_nonfatal_parse_args__no_security_tag(void)
   240  {
   241  	// Check that lack of security tag is reported as error.
   242  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   243  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   244  
   245  	int argc;
   246  	char **argv;
   247  	test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine", NULL);
   248  
   249  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   250  	g_assert_nonnull(err);
   251  	g_assert_null(args);
   252  
   253  	// Check the error that we've got
   254  	g_assert_cmpstr(sc_error_msg(err), ==,
   255  			"Usage: snap-confine <security-tag> <executable>\n"
   256  			"\napplication or hook security tag was not provided");
   257  
   258  	g_assert_true(sc_error_match(err, SC_ARGS_DOMAIN, SC_ARGS_ERR_USAGE));
   259  }
   260  
   261  static void test_sc_nonfatal_parse_args__no_executable(void)
   262  {
   263  	// Check that lack of security tag is reported as error.
   264  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   265  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   266  
   267  	int argc;
   268  	char **argv;
   269  	test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine",
   270  		       "snap.SNAP_NAME.APP_NAME", NULL);
   271  
   272  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   273  	g_assert_nonnull(err);
   274  	g_assert_null(args);
   275  
   276  	// Check the error that we've got
   277  	g_assert_cmpstr(sc_error_msg(err), ==,
   278  			"Usage: snap-confine <security-tag> <executable>\n"
   279  			"\nexecutable name was not provided");
   280  	g_assert_true(sc_error_match(err, SC_ARGS_DOMAIN, SC_ARGS_ERR_USAGE));
   281  }
   282  
   283  static void test_sc_nonfatal_parse_args__unknown_option(void)
   284  {
   285  	// Check that unrecognized option switch is reported as error.
   286  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   287  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   288  
   289  	int argc;
   290  	char **argv;
   291  	test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine",
   292  		       "--frozbonicator", NULL);
   293  
   294  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   295  	g_assert_nonnull(err);
   296  	g_assert_null(args);
   297  
   298  	// Check the error that we've got
   299  	g_assert_cmpstr(sc_error_msg(err), ==,
   300  			"Usage: snap-confine <security-tag> <executable>\n"
   301  			"\nunrecognized command line option: --frozbonicator");
   302  	g_assert_true(sc_error_match(err, SC_ARGS_DOMAIN, SC_ARGS_ERR_USAGE));
   303  }
   304  
   305  static void test_sc_nonfatal_parse_args__forwards_error(void)
   306  {
   307  	// Check that sc_nonfatal_parse_args() forwards errors.
   308  	if (g_test_subprocess()) {
   309  		int argc;
   310  		char **argv;
   311  		test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine",
   312  			       "--frozbonicator", NULL);
   313  
   314  		// Call sc_nonfatal_parse_args() without an error handle
   315  		struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   316  		args = sc_nonfatal_parse_args(&argc, &argv, NULL);
   317  		(void)args;
   318  
   319  		g_test_message("expected not to reach this place");
   320  		g_test_fail();
   321  		return;
   322  	}
   323  	g_test_trap_subprocess(NULL, 0, 0);
   324  	g_test_trap_assert_failed();
   325  	g_test_trap_assert_stderr
   326  	    ("Usage: snap-confine <security-tag> <executable>\n"
   327  	     "\nunrecognized command line option: --frozbonicator\n");
   328  }
   329  
   330  static void test_sc_nonfatal_parse_args__base_snap(void)
   331  {
   332  	// Check that --base specifies the name of the base snap.
   333  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   334  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   335  
   336  	int argc;
   337  	char **argv;
   338  	test_argc_argv(&argc, &argv,
   339  		       "/usr/lib/snapd/snap-confine", "--base", "base-snap",
   340  		       "snap.SNAP_NAME.APP_NAME", "/usr/lib/snapd/snap-exec",
   341  		       NULL);
   342  
   343  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   344  	g_assert_null(err);
   345  	g_assert_nonnull(args);
   346  
   347  	// Check the --base switch
   348  	g_assert_cmpstr(sc_args_base_snap(args), ==, "base-snap");
   349  	// Check other arguments
   350  	g_assert_cmpstr(sc_args_security_tag(args), ==,
   351  			"snap.SNAP_NAME.APP_NAME");
   352  	g_assert_cmpstr(sc_args_executable(args), ==,
   353  			"/usr/lib/snapd/snap-exec");
   354  	g_assert_cmpint(sc_args_is_version_query(args), ==, false);
   355  	g_assert_cmpint(sc_args_is_classic_confinement(args), ==, false);
   356  }
   357  
   358  static void test_sc_nonfatal_parse_args__base_snap__missing_arg(void)
   359  {
   360  	// Check that --base specifies the name of the base snap.
   361  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   362  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   363  
   364  	int argc;
   365  	char **argv;
   366  	test_argc_argv(&argc, &argv,
   367  		       "/usr/lib/snapd/snap-confine", "--base", NULL);
   368  
   369  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   370  	g_assert_nonnull(err);
   371  	g_assert_null(args);
   372  
   373  	// Check the error that we've got
   374  	g_assert_cmpstr(sc_error_msg(err), ==,
   375  			"Usage: snap-confine <security-tag> <executable>\n"
   376  			"\nthe --base option requires an argument");
   377  	g_assert_true(sc_error_match(err, SC_ARGS_DOMAIN, SC_ARGS_ERR_USAGE));
   378  }
   379  
   380  static void test_sc_nonfatal_parse_args__base_snap__twice(void)
   381  {
   382  	// Check that --base specifies the name of the base snap.
   383  	sc_error *err SC_CLEANUP(sc_cleanup_error) = NULL;
   384  	struct sc_args *args SC_CLEANUP(sc_cleanup_args) = NULL;
   385  
   386  	int argc;
   387  	char **argv;
   388  	test_argc_argv(&argc, &argv,
   389  		       "/usr/lib/snapd/snap-confine",
   390  		       "--base", "base1", "--base", "base2", NULL);
   391  
   392  	args = sc_nonfatal_parse_args(&argc, &argv, &err);
   393  	g_assert_nonnull(err);
   394  	g_assert_null(args);
   395  
   396  	// Check the error that we've got
   397  	g_assert_cmpstr(sc_error_msg(err), ==,
   398  			"Usage: snap-confine <security-tag> <executable>\n"
   399  			"\nthe --base option can be used only once");
   400  	g_assert_true(sc_error_match(err, SC_ARGS_DOMAIN, SC_ARGS_ERR_USAGE));
   401  }
   402  
   403  static void __attribute__((constructor)) init(void)
   404  {
   405  	g_test_add_func("/args/sc_cleanup_args", test_sc_cleanup_args);
   406  	g_test_add_func("/args/sc_nonfatal_parse_args/typical",
   407  			test_sc_nonfatal_parse_args__typical);
   408  	g_test_add_func("/args/sc_nonfatal_parse_args/typical_classic",
   409  			test_sc_nonfatal_parse_args__typical_classic);
   410  	g_test_add_func("/args/sc_nonfatal_parse_args/ubuntu_core_launcher",
   411  			test_sc_nonfatal_parse_args__ubuntu_core_launcher);
   412  	g_test_add_func("/args/sc_nonfatal_parse_args/version",
   413  			test_sc_nonfatal_parse_args__version);
   414  	g_test_add_func("/args/sc_nonfatal_parse_args/nothing_to_parse",
   415  			test_sc_nonfatal_parse_args__nothing_to_parse);
   416  	g_test_add_func("/args/sc_nonfatal_parse_args/evil_input",
   417  			test_sc_nonfatal_parse_args__evil_input);
   418  	g_test_add_func("/args/sc_nonfatal_parse_args/no_security_tag",
   419  			test_sc_nonfatal_parse_args__no_security_tag);
   420  	g_test_add_func("/args/sc_nonfatal_parse_args/no_executable",
   421  			test_sc_nonfatal_parse_args__no_executable);
   422  	g_test_add_func("/args/sc_nonfatal_parse_args/unknown_option",
   423  			test_sc_nonfatal_parse_args__unknown_option);
   424  	g_test_add_func("/args/sc_nonfatal_parse_args/forwards_error",
   425  			test_sc_nonfatal_parse_args__forwards_error);
   426  	g_test_add_func("/args/sc_nonfatal_parse_args/base_snap",
   427  			test_sc_nonfatal_parse_args__base_snap);
   428  	g_test_add_func("/args/sc_nonfatal_parse_args/base_snap/missing-arg",
   429  			test_sc_nonfatal_parse_args__base_snap__missing_arg);
   430  	g_test_add_func("/args/sc_nonfatal_parse_args/base_snap/twice",
   431  			test_sc_nonfatal_parse_args__base_snap__twice);
   432  }