libvirt/tests/securityselinuxtest.c

346 lines
10 KiB
C

/*
* Copyright (C) 2011-2013 Red Hat, Inc.
*
* 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
* License along with this library. If not, see
* <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"
#include "viralloc.h"
#include "virlog.h"
#include "virerror.h"
#include "virfile.h"
#include "security/security_manager.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_NONE
VIR_LOG_INIT("tests.securityselinuxtest");
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;
virSecurityLabelDefPtr secdef = NULL;
if (!(def = virDomainDefNew()))
goto error;
def->virtType = VIR_DOMAIN_VIRT_KVM;
if (VIR_ALLOC_N(def->seclabels, 1) < 0)
goto error;
if (VIR_ALLOC(secdef) < 0)
goto error;
if (VIR_STRDUP(secdef->model, "selinux") < 0)
goto error;
secdef->type = dynamic ? VIR_DOMAIN_SECLABEL_DYNAMIC : VIR_DOMAIN_SECLABEL_STATIC;
if (label &&
VIR_STRDUP(secdef->label, label) < 0)
goto error;
if (baselabel &&
VIR_STRDUP(secdef->baselabel, baselabel) < 0)
goto error;
def->seclabels[0] = secdef;
def->nseclabels++;
return def;
error:
virDomainDefFree(def);
virSecurityLabelDefFree(secdef);
return NULL;
}
static bool
testSELinuxCheckCon(context_t con,
const char *user,
const char *role,
const char *type,
int sensMin,
int sensMax G_GNUC_UNUSED,
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;
if (setcon_raw((security_context_t)data->pidcon) < 0) {
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) {
fprintf(stderr, "Cannot generate label: %s\n", virGetLastErrorMessage());
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;
cleanup:
context_free(con);
context_free(imgcon);
virDomainDefFree(def);
return ret;
}
static int
mymain(void)
{
int ret = 0;
virSecurityManagerPtr mgr;
if (!(mgr = virSecurityManagerNew("selinux", "QEMU",
VIR_SECURITY_MANAGER_DEFAULT_CONFINED |
VIR_SECURITY_MANAGER_PRIVILEGED))) {
fprintf(stderr, "Unable to initialize security driver: %s\n",
virGetLastErrorMessage());
return EXIT_FAILURE;
}
#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 \
}; \
if (virTestRun("GenLabel " # desc, testSELinuxGenLabel, &data) < 0) \
ret = -1; \
} while (0)
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);
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);
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);
virObjectUnref(mgr);
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
VIR_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/libsecurityselinuxhelper.so")