1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Test which characters may delimit the fields of a register string. 4 */ 5 #define _GNU_SOURCE 6 #include <stdio.h> 7 #include <stdlib.h> 8 9 #include "binfmt_misc_common.h" 10 #include "kselftest_harness.h" 11 12 #define ENTRY "bmdelim" 13 /* Shares no character with the sets below, or a refusal proves nothing. */ 14 #define MAGIC "bmmagic" 15 #define INTERP "/bin/true" 16 17 /* 18 * ASCII punctuation without '\' and '/'. The backslash is refused because 19 * it would cut a magic that uses \x to escape short. '/' is accepted 20 * but cannot delimit a rule that names an absolute interpreter. 21 */ 22 #define PUNCTUATION "!\"#$%&'()*+,-.:;<=>?@[]^_`{|}~" 23 24 /* 'M', 'E' and 'B' name types, 'P' through 'D' are the flags. */ 25 #define LETTERS "MEBPOCFTLDqz" 26 #define DIGITS "0157" 27 #define WHITESPACE " \t\n" 28 #define CONTROL "\001\033\177" 29 #define NON_ASCII "\200\244\377" 30 31 /* ':bmdelim:E::bmmagic::/bin/true:' with @del in place of every ':'. */ 32 static int register_with(char del) 33 { 34 char rule[128]; 35 36 snprintf(rule, sizeof(rule), "%c%s%cE%c%c%s%c%c%s%c", del, ENTRY, del, 37 del, del, MAGIC, del, del, INTERP, del); 38 return write_reg(rule); 39 } 40 41 /* No character of @set may delimit a register string. */ 42 static void expect_refused(struct __test_metadata *_metadata, const char *set) 43 { 44 const char *d; 45 46 for (d = set; *d; d++) { 47 int rc = register_with(*d); 48 49 EXPECT_EQ(rc, -1) 50 TH_LOG("%#x delimited a register string", 51 (unsigned char)*d); 52 if (rc == 0) { 53 unregister(ENTRY); 54 continue; 55 } 56 EXPECT_EQ(errno, EINVAL); 57 } 58 } 59 60 FIXTURE(delim) { 61 }; 62 63 FIXTURE_SETUP(delim) 64 { 65 if (getuid() != 0) 66 SKIP(return, "test must be run as root"); 67 if (!binfmt_misc_available()) 68 SKIP(return, "no binfmt_misc"); 69 70 /* A kernel without the allow-list takes any character but a flag. */ 71 if (register_with('q') == 0) { 72 unregister(ENTRY); 73 SKIP(return, "kernel without the delimiter allow-list"); 74 } 75 } 76 77 FIXTURE_TEARDOWN(delim) 78 { 79 unregister(ENTRY); 80 } 81 82 /* Punctuation delimits, which is all anything deployed ever uses. */ 83 TEST_F(delim, punctuation_accepted) 84 { 85 const char *d; 86 87 for (d = PUNCTUATION; *d; d++) { 88 EXPECT_EQ(register_with(*d), 0) 89 TH_LOG("'%c' refused with errno %d", *d, errno); 90 unregister(ENTRY); 91 } 92 } 93 94 /* Letters name the types and the flags, so none of them can delimit. */ 95 TEST_F(delim, letters_refused) 96 { 97 expect_refused(_metadata, LETTERS); 98 } 99 100 /* The offset field is written in digits. */ 101 TEST_F(delim, digits_refused) 102 { 103 expect_refused(_metadata, DIGITS); 104 } 105 106 TEST_F(delim, whitespace_refused) 107 { 108 expect_refused(_metadata, WHITESPACE); 109 } 110 111 TEST_F(delim, control_refused) 112 { 113 expect_refused(_metadata, CONTROL); 114 } 115 116 TEST_F(delim, non_ascii_refused) 117 { 118 expect_refused(_metadata, NON_ASCII); 119 } 120 121 /* The escape character would cut every magic that uses one short. */ 122 TEST_F(delim, backslash_refused) 123 { 124 expect_refused(_metadata, "\\"); 125 } 126 127 TEST_HARNESS_MAIN 128