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