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 }