1 /*
2 * Copyright (C) 2011-2014 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * License along with this library; If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21
22 #include <config.h>
23
24 #include <time.h>
25
26 #include <selinux/selinux.h>
27 #include <selinux/context.h>
28 #include <sys/xattr.h>
29
30 #include "internal.h"
31 #include "testutils.h"
32 #include "testutilsqemu.h"
33 #include "qemu/qemu_domain.h"
34 #include "viralloc.h"
35 #include "virerror.h"
36 #include "virfile.h"
37 #include "virlog.h"
38 #include "security/security_manager.h"
39 #include "virstring.h"
40
41 #define VIR_FROM_THIS VIR_FROM_NONE
42
43 VIR_LOG_INIT("tests.securityselinuxlabeltest");
44
45 static virQEMUDriver driver;
46
47 static virSecurityManager *mgr;
48
49 typedef struct testSELinuxFile testSELinuxFile;
50
51 struct testSELinuxFile {
52 char *file;
53 char *context;
54 };
55
56 static int
testUserXattrEnabled(void)57 testUserXattrEnabled(void)
58 {
59 int ret = -1;
60 ssize_t len;
61 const char *con_value = "system_u:object_r:svirt_image_t:s0:c41,c264";
62 g_autofree char *path = NULL;
63 path = g_strdup_printf("%s/securityselinuxlabeldata/testxattr", abs_builddir);
64
65 if (g_mkdir_with_parents(abs_builddir "/securityselinuxlabeldata", 0777) < 0 ||
66 virFileTouch(path, 0600) < 0)
67 goto cleanup;
68
69 len = setxattr(path, "user.libvirt.selinux", con_value,
70 strlen(con_value), 0);
71 if (len < 0) {
72 if (errno == EOPNOTSUPP)
73 ret = 0;
74 goto cleanup;
75 }
76
77 ret = 1;
78
79 cleanup:
80 unlink(path);
81 rmdir(abs_builddir "/securityselinuxlabeldata");
82 return ret;
83 }
84
85 static int
testSELinuxMungePath(char ** path)86 testSELinuxMungePath(char **path)
87 {
88 char *tmp;
89
90 tmp = g_strdup_printf("%s/securityselinuxlabeldata%s", abs_builddir, *path);
91
92 VIR_FREE(*path);
93 *path = tmp;
94 return 0;
95 }
96
97 static int
testSELinuxLoadFileList(const char * testname,testSELinuxFile ** files,size_t * nfiles)98 testSELinuxLoadFileList(const char *testname,
99 testSELinuxFile **files,
100 size_t *nfiles)
101 {
102 g_autofree char *path = NULL;
103 g_autoptr(FILE) fp = NULL;
104 g_autofree char *line = NULL;
105
106 *files = NULL;
107 *nfiles = 0;
108
109 path = g_strdup_printf("%s/securityselinuxlabeldata/%s.txt", abs_srcdir,
110 testname);
111
112 if (!(fp = fopen(path, "r")))
113 return -1;
114
115 line = g_new0(char, 1024);
116
117 while (!feof(fp)) {
118 char *file = NULL, *context = NULL, *tmp;
119 if (!fgets(line, 1024, fp)) {
120 if (!feof(fp))
121 return -1;
122 break;
123 }
124
125 tmp = strchr(line, ';');
126 if (!tmp) {
127 virReportError(VIR_ERR_INTERNAL_ERROR,
128 "unexpected format for line '%s'",
129 line);
130 return -1;
131 }
132 *tmp = '\0';
133 tmp++;
134
135 file = g_strdup_printf("%s/securityselinuxlabeldata%s", abs_builddir,
136 line);
137 if (*tmp != '\0' && *tmp != '\n') {
138 context = g_strdup(tmp);
139
140 tmp = strchr(context, '\n');
141 if (tmp)
142 *tmp = '\0';
143 }
144
145 VIR_EXPAND_N(*files, *nfiles, 1);
146 (*files)[(*nfiles)-1].file = file;
147 (*files)[(*nfiles)-1].context = context;
148 }
149
150 return 0;
151 }
152
153
154 static virDomainDef *
testSELinuxLoadDef(const char * testname)155 testSELinuxLoadDef(const char *testname)
156 {
157 char *xmlfile = NULL;
158 virDomainDef *def = NULL;
159 size_t i;
160
161 xmlfile = g_strdup_printf("%s/securityselinuxlabeldata/%s.xml", abs_srcdir,
162 testname);
163
164 if (!(def = virDomainDefParseFile(xmlfile, driver.xmlopt,
165 NULL, 0)))
166 goto cleanup;
167
168 for (i = 0; i < def->ndisks; i++) {
169 if (def->disks[i]->src->type != VIR_STORAGE_TYPE_FILE &&
170 def->disks[i]->src->type != VIR_STORAGE_TYPE_BLOCK)
171 continue;
172
173 if (testSELinuxMungePath(&def->disks[i]->src->path) < 0)
174 goto cleanup;
175 }
176
177 for (i = 0; i < def->nserials; i++) {
178 if (def->serials[i]->source->type != VIR_DOMAIN_CHR_TYPE_FILE &&
179 def->serials[i]->source->type != VIR_DOMAIN_CHR_TYPE_PIPE &&
180 def->serials[i]->source->type != VIR_DOMAIN_CHR_TYPE_DEV &&
181 def->serials[i]->source->type != VIR_DOMAIN_CHR_TYPE_UNIX)
182 continue;
183
184 if (def->serials[i]->source->type == VIR_DOMAIN_CHR_TYPE_UNIX) {
185 if (testSELinuxMungePath(&def->serials[i]->source->data.nix.path) < 0)
186 goto cleanup;
187 } else {
188 if (testSELinuxMungePath(&def->serials[i]->source->data.file.path) < 0)
189 goto cleanup;
190 }
191 }
192
193 if (def->os.kernel &&
194 testSELinuxMungePath(&def->os.kernel) < 0)
195 goto cleanup;
196 if (def->os.initrd &&
197 testSELinuxMungePath(&def->os.initrd) < 0)
198 goto cleanup;
199
200 cleanup:
201 VIR_FREE(xmlfile);
202 return def;
203 }
204
205
206 static int
testSELinuxCreateDisks(testSELinuxFile * files,size_t nfiles)207 testSELinuxCreateDisks(testSELinuxFile *files, size_t nfiles)
208 {
209 size_t i;
210
211 if (g_mkdir_with_parents(abs_builddir "/securityselinuxlabeldata/nfs", 0777) < 0)
212 return -1;
213
214 for (i = 0; i < nfiles; i++) {
215 if (virFileTouch(files[i].file, 0600) < 0)
216 return -1;
217 }
218 return 0;
219 }
220
221 static int
testSELinuxDeleteDisks(testSELinuxFile * files,size_t nfiles)222 testSELinuxDeleteDisks(testSELinuxFile *files, size_t nfiles)
223 {
224 size_t i;
225
226 for (i = 0; i < nfiles; i++) {
227 if (unlink(files[i].file) < 0)
228 return -1;
229 }
230 if (rmdir(abs_builddir "/securityselinuxlabeldata/nfs") < 0)
231 return -1;
232 /* Ignore failure to remove non-empty directory with in-tree build */
233 rmdir(abs_builddir "/securityselinuxlabeldata");
234 return 0;
235 }
236
237 static int
testSELinuxCheckLabels(testSELinuxFile * files,size_t nfiles)238 testSELinuxCheckLabels(testSELinuxFile *files, size_t nfiles)
239 {
240 size_t i;
241
242 for (i = 0; i < nfiles; i++) {
243 g_autofree char *ctx = NULL;
244 if (getfilecon(files[i].file, &ctx) < 0) {
245 if (errno == ENODATA) {
246 /* nothing to do */
247 } else if (errno == EOPNOTSUPP) {
248 ctx = g_strdup("EOPNOTSUPP");
249 } else {
250 virReportSystemError(errno,
251 "Cannot read label on %s",
252 files[i].file);
253 return -1;
254 }
255 }
256 if (STRNEQ_NULLABLE(files[i].context, ctx)) {
257 virReportError(VIR_ERR_INTERNAL_ERROR,
258 "File %s context '%s' did not match expected '%s'",
259 files[i].file, ctx, files[i].context);
260 return -1;
261 }
262 }
263 return 0;
264 }
265
266 static int
testSELinuxLabeling(const void * opaque)267 testSELinuxLabeling(const void *opaque)
268 {
269 const char *testname = opaque;
270 int ret = -1;
271 testSELinuxFile *files = NULL;
272 size_t nfiles = 0;
273 size_t i;
274 g_autoptr(virDomainDef) def = NULL;
275
276 if (testSELinuxLoadFileList(testname, &files, &nfiles) < 0)
277 goto cleanup;
278
279 if (testSELinuxCreateDisks(files, nfiles) < 0)
280 goto cleanup;
281
282 if (!(def = testSELinuxLoadDef(testname)))
283 goto cleanup;
284
285 if (virSecurityManagerSetAllLabel(mgr, def, NULL, false, false) < 0)
286 goto cleanup;
287
288 if (testSELinuxCheckLabels(files, nfiles) < 0)
289 goto cleanup;
290
291 ret = 0;
292
293 cleanup:
294 if (testSELinuxDeleteDisks(files, nfiles) < 0)
295 VIR_WARN("unable to fully clean up");
296
297 for (i = 0; i < nfiles; i++) {
298 VIR_FREE(files[i].file);
299 VIR_FREE(files[i].context);
300 }
301 VIR_FREE(files);
302 if (ret < 0)
303 VIR_TEST_VERBOSE("%s", virGetLastErrorMessage());
304 return ret;
305 }
306
307
308
309 static int
mymain(void)310 mymain(void)
311 {
312 int ret = 0;
313 int rc = testUserXattrEnabled();
314 g_autoptr(virQEMUCaps) qemuCaps = NULL;
315
316 if (rc < 0) {
317 VIR_TEST_VERBOSE("failed to determine xattr support");
318 return EXIT_FAILURE;
319 }
320
321 if (rc == 0) {
322 VIR_TEST_VERBOSE("xattr unsupported");
323 return EXIT_AM_SKIP;
324 }
325
326 if (!(mgr = virSecurityManagerNew("selinux", "QEMU",
327 VIR_SECURITY_MANAGER_DEFAULT_CONFINED |
328 VIR_SECURITY_MANAGER_PRIVILEGED))) {
329 VIR_TEST_VERBOSE("Unable to initialize security driver: %s",
330 virGetLastErrorMessage());
331 return EXIT_FAILURE;
332 }
333
334 if (qemuTestDriverInit(&driver) < 0)
335 return EXIT_FAILURE;
336
337 if (!(qemuCaps = virQEMUCapsNew()))
338 return EXIT_FAILURE;
339
340 virQEMUCapsSet(qemuCaps, QEMU_CAPS_DEVICE_CIRRUS_VGA);
341 virQEMUCapsSet(qemuCaps, QEMU_CAPS_VNC);
342
343 if (qemuTestCapsCacheInsert(driver.qemuCapsCache, qemuCaps) < 0)
344 return EXIT_FAILURE;
345
346 #define DO_TEST_LABELING(name) \
347 if (virTestRun("Labelling " # name, testSELinuxLabeling, name) < 0) \
348 ret = -1;
349
350 setcon("system_r:system_u:libvirtd_t:s0:c0.c1023");
351
352 DO_TEST_LABELING("disks");
353 DO_TEST_LABELING("kernel");
354 DO_TEST_LABELING("chardev");
355 DO_TEST_LABELING("nfs");
356
357 qemuTestDriverFree(&driver);
358
359 return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
360 }
361
362 VIR_TEST_MAIN_PRELOAD(mymain,
363 VIR_TEST_MOCK("domaincaps"),
364 abs_builddir "/libsecurityselinuxhelper.so")
365