2012-08-10 13:31:14 +00:00
|
|
|
/*
|
2013-02-22 22:42:39 +00:00
|
|
|
* Copyright (C) 2011-2013 Red Hat, Inc.
|
2012-08-10 13:31:14 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-08-10 13:31:14 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include <selinux/selinux.h>
|
|
|
|
#include <selinux/context.h>
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
#include "testutils.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2013-05-09 18:59:04 +00:00
|
|
|
#include "virfile.h"
|
2012-08-10 13:31:14 +00:00
|
|
|
#include "security/security_manager.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2012-08-10 13:31:14 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("tests.securityselinuxtest");
|
|
|
|
|
2012-08-10 13:31:14 +00:00
|
|
|
struct testSELinuxGenLabelData {
|
|
|
|
virSecurityManagerPtr mgr;
|
|
|
|
|
|
|
|
const char *pidcon;
|
|
|
|
|
|
|
|
bool dynamic;
|
|
|
|
const char *label;
|
|
|
|
const char *baselabel;
|
|
|
|
|
|
|
|
const char *user;
|
|
|
|
const char *role;
|
|
|
|
const char *imagerole;
|
|
|
|
const char *type;
|
|
|
|
const char *imagetype;
|
|
|
|
|
|
|
|
int sensMin;
|
|
|
|
int sensMax;
|
|
|
|
int catMin;
|
|
|
|
int catMax;
|
|
|
|
};
|
|
|
|
|
|
|
|
static virDomainDefPtr
|
|
|
|
testBuildDomainDef(bool dynamic,
|
|
|
|
const char *label,
|
|
|
|
const char *baselabel)
|
|
|
|
{
|
|
|
|
virDomainDefPtr def;
|
2017-08-23 16:32:23 +00:00
|
|
|
virSecurityLabelDefPtr secdef = NULL;
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2015-02-16 15:30:11 +00:00
|
|
|
if (!(def = virDomainDefNew()))
|
2013-07-04 10:20:21 +00:00
|
|
|
goto error;
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2017-08-16 21:45:54 +00:00
|
|
|
def->virtType = VIR_DOMAIN_VIRT_KVM;
|
2020-09-22 23:04:17 +00:00
|
|
|
def->seclabels = g_new0(virSecurityLabelDefPtr, 1);
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2020-09-22 22:42:45 +00:00
|
|
|
secdef = g_new0(virSecurityLabelDef, 1);
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
secdef->model = g_strdup("selinux");
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2017-08-16 21:45:54 +00:00
|
|
|
secdef->type = dynamic ? VIR_DOMAIN_SECLABEL_DYNAMIC : VIR_DOMAIN_SECLABEL_STATIC;
|
2019-10-20 11:49:46 +00:00
|
|
|
if (label)
|
|
|
|
secdef->label = g_strdup(label);
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
if (baselabel)
|
|
|
|
secdef->baselabel = g_strdup(baselabel);
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2017-08-16 21:45:54 +00:00
|
|
|
def->seclabels[0] = secdef;
|
|
|
|
def->nseclabels++;
|
2012-08-10 13:31:14 +00:00
|
|
|
return def;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
error:
|
2012-08-10 13:31:14 +00:00
|
|
|
virDomainDefFree(def);
|
2017-08-23 16:32:23 +00:00
|
|
|
virSecurityLabelDefFree(secdef);
|
2012-08-10 13:31:14 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
testSELinuxCheckCon(context_t con,
|
|
|
|
const char *user,
|
|
|
|
const char *role,
|
|
|
|
const char *type,
|
|
|
|
int sensMin,
|
2019-10-14 12:45:03 +00:00
|
|
|
int sensMax G_GNUC_UNUSED,
|
2012-08-10 13:31:14 +00:00
|
|
|
int catMin,
|
|
|
|
int catMax)
|
|
|
|
{
|
|
|
|
const char *range;
|
|
|
|
char *tmp;
|
|
|
|
int gotSens;
|
|
|
|
int gotCatOne;
|
|
|
|
int gotCatTwo;
|
|
|
|
|
|
|
|
if (STRNEQ(context_user_get(con), user)) {
|
|
|
|
fprintf(stderr, "Expect user %s got %s\n",
|
|
|
|
user, context_user_get(con));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (STRNEQ(context_role_get(con), role)) {
|
|
|
|
fprintf(stderr, "Expect role %s got %s\n",
|
|
|
|
role, context_role_get(con));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (STRNEQ(context_type_get(con), type)) {
|
|
|
|
fprintf(stderr, "Expect type %s got %s\n",
|
|
|
|
type, context_type_get(con));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
range = context_range_get(con);
|
|
|
|
if (range[0] != 's') {
|
|
|
|
fprintf(stderr, "Malformed range %s, cannot find sensitivity\n",
|
|
|
|
range);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (virStrToLong_i(range + 1, &tmp, 10, &gotSens) < 0 ||
|
|
|
|
!tmp) {
|
|
|
|
fprintf(stderr, "Malformed range %s, cannot parse sensitivity\n",
|
|
|
|
range + 1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (*tmp != ':') {
|
|
|
|
fprintf(stderr, "Malformed range %s, too many sensitivity values\n",
|
|
|
|
tmp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
tmp++;
|
|
|
|
if (*tmp != 'c') {
|
|
|
|
fprintf(stderr, "Malformed range %s, cannot find first category\n",
|
|
|
|
tmp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
tmp++;
|
|
|
|
if (virStrToLong_i(tmp, &tmp, 10, &gotCatOne) < 0) {
|
|
|
|
fprintf(stderr, "Malformed range %s, cannot parse category one\n",
|
|
|
|
tmp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (tmp && *tmp == ',')
|
|
|
|
tmp++;
|
|
|
|
if (tmp && *tmp == 'c') {
|
|
|
|
tmp++;
|
|
|
|
if (virStrToLong_i(tmp, &tmp, 10, &gotCatTwo) < 0) {
|
|
|
|
fprintf(stderr, "Malformed range %s, cannot parse category two\n",
|
|
|
|
tmp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (*tmp != '\0') {
|
|
|
|
fprintf(stderr, "Malformed range %s, junk after second category\n",
|
|
|
|
tmp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (gotCatOne == gotCatTwo) {
|
|
|
|
fprintf(stderr, "Saw category pair %d,%d where cats were equal\n",
|
|
|
|
gotCatOne, gotCatTwo);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
gotCatTwo = gotCatOne;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gotSens != sensMin) {
|
|
|
|
fprintf(stderr, "Sensitivity %d is not equal to min %d\n",
|
|
|
|
gotSens, sensMin);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (gotCatOne < catMin ||
|
|
|
|
gotCatOne > catMax) {
|
|
|
|
fprintf(stderr, "Category one %d is out of range %d-%d\n",
|
|
|
|
gotCatTwo, catMin, catMax);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (gotCatTwo < catMin ||
|
|
|
|
gotCatTwo > catMax) {
|
|
|
|
fprintf(stderr, "Category two %d is out of range %d-%d\n",
|
|
|
|
gotCatTwo, catMin, catMax);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gotCatOne > gotCatTwo) {
|
|
|
|
fprintf(stderr, "Category one %d is greater than category two %d\n",
|
|
|
|
gotCatOne, gotCatTwo);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
testSELinuxGenLabel(const void *opaque)
|
|
|
|
{
|
|
|
|
const struct testSELinuxGenLabelData *data = opaque;
|
|
|
|
int ret = -1;
|
|
|
|
virDomainDefPtr def;
|
|
|
|
context_t con = NULL;
|
|
|
|
context_t imgcon = NULL;
|
|
|
|
|
2020-07-15 10:32:48 +00:00
|
|
|
if (setcon_raw(data->pidcon) < 0) {
|
2012-08-10 13:31:14 +00:00
|
|
|
perror("Cannot set process security context");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(def = testBuildDomainDef(data->dynamic,
|
|
|
|
data->label,
|
|
|
|
data->baselabel)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virSecurityManagerGenLabel(data->mgr, def) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
fprintf(stderr, "Cannot generate label: %s\n", virGetLastErrorMessage());
|
2012-08-10 13:31:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("label=%s imagelabel=%s",
|
|
|
|
def->seclabels[0]->label, def->seclabels[0]->imagelabel);
|
|
|
|
|
|
|
|
if (!(con = context_new(def->seclabels[0]->label)))
|
|
|
|
goto cleanup;
|
|
|
|
if (!(imgcon = context_new(def->seclabels[0]->imagelabel)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!testSELinuxCheckCon(con,
|
|
|
|
data->user, data->role, data->type,
|
|
|
|
data->sensMin, data->sensMax,
|
|
|
|
data->catMin, data->catMax))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!testSELinuxCheckCon(imgcon,
|
|
|
|
data->user, data->imagerole, data->imagetype,
|
|
|
|
data->sensMin, data->sensMax,
|
|
|
|
data->catMin, data->catMax))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2012-08-10 13:31:14 +00:00
|
|
|
context_free(con);
|
|
|
|
context_free(imgcon);
|
|
|
|
virDomainDefFree(def);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
mymain(void)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
virSecurityManagerPtr mgr;
|
|
|
|
|
2018-10-02 13:08:28 +00:00
|
|
|
if (!(mgr = virSecurityManagerNew("selinux", "QEMU",
|
2015-10-06 15:01:48 +00:00
|
|
|
VIR_SECURITY_MANAGER_DEFAULT_CONFINED |
|
|
|
|
VIR_SECURITY_MANAGER_PRIVILEGED))) {
|
2012-08-10 13:31:14 +00:00
|
|
|
fprintf(stderr, "Unable to initialize security driver: %s\n",
|
2016-05-19 19:10:18 +00:00
|
|
|
virGetLastErrorMessage());
|
2013-02-22 22:42:39 +00:00
|
|
|
return EXIT_FAILURE;
|
2012-08-10 13:31:14 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define DO_TEST_GEN_LABEL(desc, pidcon, \
|
|
|
|
dynamic, label, baselabel, \
|
|
|
|
user, role, imageRole, \
|
|
|
|
type, imageType, \
|
|
|
|
sensMin, sensMax, catMin, catMax) \
|
|
|
|
do { \
|
|
|
|
struct testSELinuxGenLabelData data = { \
|
|
|
|
mgr, pidcon, dynamic, label, baselabel, \
|
|
|
|
user, role, imageRole, type, imageType, \
|
|
|
|
sensMin, sensMax, catMin, catMax \
|
|
|
|
}; \
|
2016-05-26 15:01:50 +00:00
|
|
|
if (virTestRun("GenLabel " # desc, testSELinuxGenLabel, &data) < 0) \
|
2017-11-03 12:09:47 +00:00
|
|
|
ret = -1; \
|
2012-08-10 13:31:14 +00:00
|
|
|
} while (0)
|
|
|
|
|
2013-03-13 17:58:26 +00:00
|
|
|
DO_TEST_GEN_LABEL("dynamic unconfined, s0, c0.c1023",
|
|
|
|
"unconfined_u:unconfined_r:unconfined_t:s0",
|
|
|
|
true, NULL, NULL,
|
|
|
|
"unconfined_u", "unconfined_r", "object_r",
|
|
|
|
"svirt_t", "svirt_image_t",
|
|
|
|
0, 0, 0, 1023);
|
|
|
|
DO_TEST_GEN_LABEL("dynamic unconfined, s0, c0.c1023",
|
|
|
|
"unconfined_u:unconfined_r:unconfined_t:s0-s0",
|
|
|
|
true, NULL, NULL,
|
|
|
|
"unconfined_u", "unconfined_r", "object_r",
|
|
|
|
"svirt_t", "svirt_image_t",
|
|
|
|
0, 0, 0, 1023);
|
2012-08-10 13:31:14 +00:00
|
|
|
DO_TEST_GEN_LABEL("dynamic unconfined, s0, c0.c1023",
|
|
|
|
"unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023",
|
|
|
|
true, NULL, NULL,
|
|
|
|
"unconfined_u", "unconfined_r", "object_r",
|
|
|
|
"svirt_t", "svirt_image_t",
|
|
|
|
0, 0, 0, 1023);
|
|
|
|
DO_TEST_GEN_LABEL("dynamic virtd, s0, c0.c1023",
|
|
|
|
"system_u:system_r:virtd_t:s0-s0:c0.c1023",
|
|
|
|
true, NULL, NULL,
|
|
|
|
"system_u", "system_r", "object_r",
|
|
|
|
"svirt_t", "svirt_image_t",
|
|
|
|
0, 0, 0, 1023);
|
|
|
|
DO_TEST_GEN_LABEL("dynamic virtd, s0, c0.c10",
|
|
|
|
"system_u:system_r:virtd_t:s0-s0:c0.c10",
|
|
|
|
true, NULL, NULL,
|
|
|
|
"system_u", "system_r", "object_r",
|
|
|
|
"svirt_t", "svirt_image_t",
|
|
|
|
0, 0, 0, 10);
|
|
|
|
DO_TEST_GEN_LABEL("dynamic virtd, s2-s3, c0.c1023",
|
|
|
|
"system_u:system_r:virtd_t:s2-s3:c0.c1023",
|
|
|
|
true, NULL, NULL,
|
|
|
|
"system_u", "system_r", "object_r",
|
|
|
|
"svirt_t", "svirt_image_t",
|
|
|
|
2, 3, 0, 1023);
|
2013-06-10 12:37:40 +00:00
|
|
|
DO_TEST_GEN_LABEL("dynamic virtd, missing range",
|
|
|
|
"system_u:system_r:virtd_t",
|
|
|
|
true, NULL, NULL,
|
|
|
|
"system_u", "system_r", "object_r",
|
|
|
|
"svirt_t", "svirt_image_t",
|
|
|
|
0, 0, 0, 1023);
|
2012-08-10 13:31:14 +00:00
|
|
|
|
2017-08-10 07:07:31 +00:00
|
|
|
virObjectUnref(mgr);
|
2012-08-10 13:31:14 +00:00
|
|
|
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2020-05-28 00:40:50 +00:00
|
|
|
VIR_TEST_MAIN_PRELOAD(mymain, abs_builddir "/libsecurityselinuxhelper.so")
|