summaryrefslogtreecommitdiff
path: root/tests/util.c
blob: f978e8a4da17cdc9279a4aa35d8ba737fcb6cc6c (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/**
 * Seccomp Library utility code for tests
 *
 * Copyright (c) 2012 Red Hat <eparis@redhat.com>
 * Author: Eric Paris <eparis@redhat.com>
 */

/*
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of version 2.1 of the GNU Lesser General Public License as
 * published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, see <http://www.gnu.org/licenses>.
 */

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <seccomp.h>

#include "util.h"

/**
 * SIGSYS signal handler
 * @param nr the signal number
 * @param info siginfo_t pointer
 * @param void_context handler context
 *
 * Simple signal handler for SIGSYS which exits with error code 161.
 *
 */
static void _trap_handler(int signal, siginfo_t *info, void *ctx)
{
	_exit(161);
}

/**
 * Add rules for gcov/lcov
 * @param ctx the filter context
 * @param action the action for the rules
 *
 * This function is to make it easier for developers to temporarily add support
 * for gcov/lcov to a test program; it likely should not be used in the normal
 * regression tests.  Further, this should only be necessary for the "live"
 * tests.
 *
 */
int util_gcov_rules(const scmp_filter_ctx ctx, int action)
{
	int rc;

	rc = seccomp_rule_add(ctx, action, SCMP_SYS(open), 0);
	if (rc != 0)
		return rc;
	rc = seccomp_rule_add(ctx, action, SCMP_SYS(openat), 0);
	if (rc != 0)
		return rc;
	rc = seccomp_rule_add(ctx, action, SCMP_SYS(fcntl), 0);
	if (rc != 0)
		return rc;
	rc = seccomp_rule_add(ctx, action, SCMP_SYS(lseek), 0);
	if (rc != 0)
		return rc;
	rc = seccomp_rule_add(ctx, action, SCMP_SYS(read), 0);
	if (rc != 0)
		return rc;
	rc = seccomp_rule_add(ctx, action, SCMP_SYS(write), 0);
	if (rc != 0)
		return rc;
	rc = seccomp_rule_add(ctx, action, SCMP_SYS(getpid), 0);
	if (rc != 0)
		return rc;

	return 0;
}

/**
 * Parse the arguments passed to main
 * @param argc the argument count
 * @param argv the argument pointer
 * @param opts the options structure
 *
 * This function parses the arguments passed to the test from the command line.
 * Returns zero on success and negative values on failure.
 *
 */
int util_getopt(int argc, char *argv[], struct util_options *opts)
{
	int rc = 0;

	if (opts == NULL)
		return -EFAULT;

	memset(opts, 0, sizeof(*opts));
	while (1) {
		int c, option_index = 0;
		const struct option long_options[] = {
			{"bpf", no_argument, &(opts->bpf_flg), 1},
			{"pfc", no_argument, &(opts->bpf_flg), 0},
			{0, 0, 0, 0},
		};

		c = getopt_long(argc, argv, "bp",
				long_options, &option_index);
		if (c == -1)
			break;

		switch (c) {
		case 0:
			break;
		case 'b':
			opts->bpf_flg = 1;
			break;
		case 'p':
			opts->bpf_flg = 0;
			break;
		default:
			rc = -EINVAL;
			break;
		}
	}

	if (rc == -EINVAL || optind < argc) {
		fprintf(stderr, "usage %s: [--bpf,-b] [--pfc,-p]\n", argv[0]);
		rc = -EINVAL;
	}

	return rc;
}

/**
 * Output the filter in either BPF or PFC
 * @param opts the options structure
 * @param ctx the filter context
 *
 * This function outputs the seccomp filter to stdout in either BPF or PFC
 * format depending on the test paramaeters supplied by @opts.
 *
 */
int util_filter_output(const struct util_options *opts,
		       const scmp_filter_ctx ctx)
{
	int rc;

	if (opts == NULL)
		return -EFAULT;

	if (opts->bpf_flg)
		rc = seccomp_export_bpf(ctx, STDOUT_FILENO);
	else
		rc = seccomp_export_pfc(ctx, STDOUT_FILENO);

	return rc;
}

/**
 * Install a TRAP action signal handler
 *
 * This function installs the TRAP action signal handler and is based on
 * examples from Will Drewry and Kees Cook.  Returns zero on success, negative
 * values on failure.
 *
 */
int util_trap_install(void)
{
	struct sigaction signal_handler;
	sigset_t signal_mask;

	memset(&signal_handler, 0, sizeof(signal_handler));
	sigemptyset(&signal_mask);
	sigaddset(&signal_mask, SIGSYS);

	signal_handler.sa_sigaction = &_trap_handler;
	signal_handler.sa_flags = SA_SIGINFO;
	if (sigaction(SIGSYS, &signal_handler, NULL) < 0)
		return -errno;
	if (sigprocmask(SIG_UNBLOCK, &signal_mask, NULL))
		return -errno;

	return 0;
}

/**
 * Parse a filter action string into an action value
 * @param action the action string
 *
 * Parse a seccomp action string into the associated integer value.  Returns
 * the correct value on success, -1 on failure.
 *
 */
int util_action_parse(const char *action)
{
	if (action == NULL)
		return -1;

	if (strcasecmp(action, "KILL") == 0)
		return SCMP_ACT_KILL;
	if (strcasecmp(action, "KILL_PROCESS") == 0)
		return SCMP_ACT_KILL_PROCESS;
	else if (strcasecmp(action, "TRAP") == 0)
		return SCMP_ACT_TRAP;
	else if (strcasecmp(action, "ERRNO") == 0)
		return SCMP_ACT_ERRNO(163);
	else if (strcasecmp(action, "TRACE") == 0)
		return -1; /* not yet supported */
	else if (strcasecmp(action, "ALLOW") == 0)
		return SCMP_ACT_ALLOW;
	else if (strcasecmp(action, "LOG") == 0)
		return SCMP_ACT_LOG;

	return -1;
}

/**
 * Write a string to a file
 * @param path the file path
 *
 * Open the specified file, write a string to the file, and close the file.
 * Return zero on success, negative values on error.
 *
 */
int util_file_write(const char *path)
{
	int fd;
	const char buf[] = "testing";
	ssize_t buf_len = strlen(buf);

	fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
	if (fd < 0)
		return -errno;
	if (write(fd, buf, buf_len) < buf_len) {
		int rc = -errno;
		close(fd);
		return rc;
	}
	if (close(fd) < 0)
		return -errno;

	return 0;
}