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