selinux/checkpolicy/checkpolicy.c
James Carter 750cc1136d
checkpolicy: Do not automatically upgrade when using "-b" flag
When reading a binary policy, do not automatically change the version
to the max policy version supported by libsepol or, if specified, the
value given using the "-c" flag.

If the binary policy version is less than or equal to version 23
(POLICYDB_VERSION_PERMISSIVE) than do not automatically upgrade the
policy and if a policy version is specified by the "-c" flag, only set
the binary policy to the specified version if it is lower than the
current version.

If the binary policy version is greater than version 23 than it should
be set to the maximum version supported by libsepol or, if specified,
the value given by the "-c" flag.

The reason for this change is that policy versions 20
(POLICYDB_VERSION_AVTAB) to 23 have a more primitive support for type
attributes where the datums are not written out, but they exist in the
type_attr_map. This means that when the binary policy is read by
libsepol, there will be gaps in the type_val_to_struct and
p_type_val_to_name arrays and policy rules can refer to those gaps.
Certain libsepol functions like sepol_kernel_policydb_to_conf() and
sepol_kernel_policydb_to_cil() do not support this behavior and need
to be able to identify these policies. Policies before version 20 do not
support attributes at all and can be handled by all libsepol functions.

Signed-off-by: James Carter <jwcart2@gmail.com>
2021-03-15 21:52:03 +01:00

1328 lines
30 KiB
C

/*
* Author : Stephen Smalley, <sds@tycho.nsa.gov>
*/
/*
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
*
* Support for enhanced MLS infrastructure.
*
* Updated: Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Updated: James Morris <jmorris@intercode.com.au>
*
* Added IPv6 support.
*
* Updated: Joshua Brindle <jbrindle@tresys.com>
* Karl MacMillan <kmacmillan@tresys.com>
* Jason Tang <jtang@tresys.com>
*
* Policy Module support.
*
* Copyright (C) 2017 Mellanox Technologies Inc.
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2005 Tresys Technology, LLC
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*/
/* FLASK */
/*
* checkpolicy
*
* Load and check a policy configuration.
*
* A policy configuration is created in a text format,
* and then compiled into a binary format for use by
* the security server. By default, checkpolicy reads
* the text format. If '-b' is specified, then checkpolicy
* reads the binary format instead.
*
* If '-o output_file' is specified, then checkpolicy
* writes the binary format version of the configuration
* to the specified output file.
*
* If '-d' is specified, then checkpolicy permits the user
* to interactively test the security server functions with
* the loaded policy configuration.
*
* If '-c' is specified, then the supplied parameter is used to
* determine which policy version to use for generating binary
* policy. This is for compatibility with older kernels. If any
* booleans or conditional rules are thrown away a warning is printed.
*/
#include <ctype.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef IPPROTO_DCCP
#define IPPROTO_DCCP 33
#endif
#ifndef IPPROTO_SCTP
#define IPPROTO_SCTP 132
#endif
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include <sepol/module_to_cil.h>
#include <sepol/kernel_to_cil.h>
#include <sepol/kernel_to_conf.h>
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/services.h>
#include <sepol/policydb/conditional.h>
#include <sepol/policydb/hierarchy.h>
#include <sepol/policydb/expand.h>
#include <sepol/policydb/link.h>
#include "queue.h"
#include "checkpolicy.h"
#include "parse_util.h"
extern char *optarg;
extern int optind;
static policydb_t policydb;
static sidtab_t sidtab;
extern policydb_t *policydbp;
extern int mlspol;
extern int werror;
static int handle_unknown = SEPOL_DENY_UNKNOWN;
static const char *txtfile = "policy.conf";
static const char *binfile = "policy";
unsigned int policyvers = 0;
static __attribute__((__noreturn__)) void usage(const char *progname)
{
printf
("usage: %s [-b[F]] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M] "
"[-c policyvers (%d-%d)] [-o output_file|-] [-S] "
"[-t target_platform (selinux,xen)] [-E] [-V] [input_file]\n",
progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
exit(1);
}
#define FGETS(out, size, in) \
if (fgets(out,size,in)==NULL) { \
fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,\
strerror(errno)); \
exit(1);\
}
static int print_sid(sepol_security_id_t sid,
context_struct_t * context
__attribute__ ((unused)), void *data
__attribute__ ((unused)))
{
sepol_security_context_t scontext;
size_t scontext_len;
int rc;
rc = sepol_sid_to_context(sid, &scontext, &scontext_len);
if (rc)
printf("sid %d -> error %d\n", sid, rc);
else {
printf("sid %d -> scontext %s\n", sid, scontext);
free(scontext);
}
return 0;
}
struct val_to_name {
unsigned int val;
char *name;
};
static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
{
struct val_to_name *v = p;
perm_datum_t *perdatum;
perdatum = (perm_datum_t *) datum;
if (v->val == perdatum->s.value) {
v->name = key;
return 1;
}
return 0;
}
#ifdef EQUIVTYPES
static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
struct avtab_node *type_rules)
{
struct avtab_node *p, *c, *n;
for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
/*
* Find the insertion point, keeping the list
* ordered by source type, then target type, then
* target class.
*/
if (k->source_type < c->key.source_type)
break;
if (k->source_type == c->key.source_type &&
k->target_type < c->key.target_type)
break;
if (k->source_type == c->key.source_type &&
k->target_type == c->key.target_type &&
k->target_class < c->key.target_class)
break;
}
/* Insert the rule */
n = malloc(sizeof(struct avtab_node));
if (!n) {
fprintf(stderr, "out of memory\n");
exit(1);
}
n->key = *k;
n->datum = *d;
n->next = p->next;
p->next = n;
return 0;
}
static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
{
struct avtab_node *type_rules = args;
if (d->specified & AVTAB_ALLOWED) {
/*
* Insert the rule into the lists for both
* the source type and the target type.
*/
if (insert_type_rule(k, d, &type_rules[k->source_type - 1]))
return -1;
if (insert_type_rule(k, d, &type_rules[k->target_type - 1]))
return -1;
}
return 0;
}
static void free_type_rules(struct avtab_node *l)
{
struct avtab_node *tmp;
while (l) {
tmp = l;
l = l->next;
free(tmp);
}
}
static int identify_equiv_types(void)
{
struct avtab_node *type_rules, *l1, *l2;
int i, j;
/*
* Create a list of access vector rules for each type
* from the access vector table.
*/
type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim);
if (!type_rules) {
fprintf(stderr, "out of memory\n");
exit(1);
}
memset(type_rules, 0,
sizeof(struct avtab_node) * policydb.p_types.nprim);
if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules))
exit(1);
/*
* Compare the type lists and identify equivalent types.
*/
for (i = 0; i < policydb.p_types.nprim - 1; i++) {
if (!type_rules[i].next)
continue;
for (j = i + 1; j < policydb.p_types.nprim; j++) {
for (l1 = type_rules[i].next, l2 = type_rules[j].next;
l1 && l2; l1 = l1->next, l2 = l2->next) {
if (l2->key.source_type == (j + 1)) {
if (l1->key.source_type != (i + 1))
break;
} else {
if (l1->key.source_type !=
l2->key.source_type)
break;
}
if (l2->key.target_type == (j + 1)) {
if (l1->key.target_type != (i + 1))
break;
} else {
if (l1->key.target_type !=
l2->key.target_type)
break;
}
if (l1->key.target_class != l2->key.target_class
|| l1->datum.allowed != l2->datum.allowed)
break;
}
if (l1 || l2)
continue;
free_type_rules(type_rules[j].next);
type_rules[j].next = NULL;
printf("Types %s and %s are equivalent.\n",
policydb.p_type_val_to_name[i],
policydb.p_type_val_to_name[j]);
}
free_type_rules(type_rules[i].next);
type_rules[i].next = NULL;
}
free(type_rules);
return 0;
}
#endif
extern char *av_to_string(uint32_t tclass, sepol_access_vector_t av);
int display_bools(void)
{
uint32_t i;
for (i = 0; i < policydbp->p_bools.nprim; i++) {
printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
policydbp->bool_val_to_struct[i]->state);
}
return 0;
}
void display_expr(cond_expr_t * exp)
{
cond_expr_t *cur;
for (cur = exp; cur != NULL; cur = cur->next) {
switch (cur->expr_type) {
case COND_BOOL:
printf("%s ",
policydbp->p_bool_val_to_name[cur->bool - 1]);
break;
case COND_NOT:
printf("! ");
break;
case COND_OR:
printf("|| ");
break;
case COND_AND:
printf("&& ");
break;
case COND_XOR:
printf("^ ");
break;
case COND_EQ:
printf("== ");
break;
case COND_NEQ:
printf("!= ");
break;
default:
printf("error!");
break;
}
}
}
int display_cond_expressions(void)
{
cond_node_t *cur;
for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
printf("expression: ");
display_expr(cur->expr);
printf("current state: %d\n", cur->cur_state);
}
return 0;
}
int change_bool(char *name, int state)
{
cond_bool_datum_t *bool;
bool = hashtab_search(policydbp->p_bools.table, name);
if (bool == NULL) {
printf("Could not find bool %s\n", name);
return -1;
}
bool->state = state;
evaluate_conds(policydbp);
return 0;
}
static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
{
level_datum_t *levdatum = (level_datum_t *) datum;
if (!levdatum->isalias && !levdatum->defined) {
fprintf(stderr,
"Error: sensitivity %s was not used in a level definition!\n",
key);
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
policydb_t parse_policy;
sepol_security_class_t tclass;
sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
sepol_security_context_t scontext;
struct sepol_av_decision avd;
class_datum_t *cladatum;
const char *file = txtfile;
char ans[80 + 1], *path, *fstype;
const char *outfile = NULL;
size_t scontext_len, pathlen;
unsigned int i;
unsigned int protocol, port;
unsigned int binary = 0, debug = 0, sort = 0, cil = 0, conf = 0, optimize = 0;
struct val_to_name v;
int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
unsigned int nel, uret;
struct stat sb;
void *map;
FILE *outfp = NULL;
char *name;
int state;
int show_version = 0;
char *reason_buf = NULL;
unsigned int reason;
int flags;
struct policy_file pf;
struct option long_options[] = {
{"output", required_argument, NULL, 'o'},
{"target", required_argument, NULL, 't'},
{"binary", no_argument, NULL, 'b'},
{"debug", no_argument, NULL, 'd'},
{"version", no_argument, NULL, 'V'},
{"handle-unknown", required_argument, NULL, 'U'},
{"mls", no_argument, NULL, 'M'},
{"cil", no_argument, NULL, 'C'},
{"conf",no_argument, NULL, 'F'},
{"sort", no_argument, NULL, 'S'},
{"optimize", no_argument, NULL, 'O'},
{"werror", no_argument, NULL, 'E'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
while ((ch = getopt_long(argc, argv, "o:t:dbU:MCFSVc:OEh", long_options, NULL)) != -1) {
switch (ch) {
case 'o':
outfile = optarg;
break;
case 't':
if (!strcasecmp(optarg, "Xen"))
target = SEPOL_TARGET_XEN;
else if (!strcasecmp(optarg, "SELinux"))
target = SEPOL_TARGET_SELINUX;
else{
fprintf(stderr, "%s: Unknown target platform:"
"%s\n", argv[0], optarg);
exit(1);
}
break;
case 'b':
binary = 1;
file = binfile;
break;
case 'd':
debug = 1;
break;
case 'V':
show_version = 1;
break;
case 'U':
if (!strcasecmp(optarg, "deny")) {
handle_unknown = DENY_UNKNOWN;
break;
}
if (!strcasecmp(optarg, "allow")) {
handle_unknown = ALLOW_UNKNOWN;
break;
}
if (!strcasecmp(optarg, "reject")) {
handle_unknown = REJECT_UNKNOWN;
break;
}
usage(argv[0]);
case 'S':
sort = 1;
break;
case 'O':
optimize = 1;
break;
case 'M':
mlspol = 1;
break;
case 'C':
cil = 1;
break;
case 'F':
conf = 1;
break;
case 'c':{
long int n;
errno = 0;
n = strtol(optarg, NULL, 10);
if (errno) {
fprintf(stderr,
"Invalid policyvers specified: %s\n",
optarg);
usage(argv[0]);
exit(1);
}
if (n < POLICYDB_VERSION_MIN
|| n > POLICYDB_VERSION_MAX) {
fprintf(stderr,
"policyvers value %ld not in range %d-%d\n",
n, POLICYDB_VERSION_MIN,
POLICYDB_VERSION_MAX);
usage(argv[0]);
exit(1);
}
if (policyvers != n)
policyvers = n;
break;
}
case 'E':
werror = 1;
break;
case 'h':
default:
usage(argv[0]);
}
}
if (show_version) {
printf("%d (compatibility range %d-%d)\n",
policyvers ? policyvers : POLICYDB_VERSION_MAX ,
POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
exit(0);
}
if (optind != argc) {
file = argv[optind++];
if (optind != argc)
usage(argv[0]);
}
/* Set policydb and sidtab used by libsepol service functions
to my structures, so that I can directly populate and
manipulate them. */
sepol_set_policydb(&policydb);
sepol_set_sidtab(&sidtab);
if (cil && conf) {
fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n");
exit(1);
}
if (binary) {
fd = open(file, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Can't open '%s': %s\n",
file, strerror(errno));
exit(1);
}
if (fstat(fd, &sb) < 0) {
fprintf(stderr, "Can't stat '%s': %s\n",
file, strerror(errno));
exit(1);
}
map =
mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
fd, 0);
if (map == MAP_FAILED) {
fprintf(stderr, "Can't map '%s': %s\n",
file, strerror(errno));
exit(1);
}
policy_file_init(&pf);
pf.type = PF_USE_MEMORY;
pf.data = map;
pf.len = sb.st_size;
if (policydb_init(&policydb)) {
fprintf(stderr, "%s: policydb_init: Out of memory!\n",
argv[0]);
exit(1);
}
ret = policydb_read(&policydb, &pf, 1);
if (ret) {
fprintf(stderr,
"%s: error(s) encountered while parsing configuration\n",
argv[0]);
exit(1);
}
policydbp = &policydb;
/* Check Policy Consistency */
if (policydbp->mls) {
if (!mlspol) {
fprintf(stderr, "%s: MLS policy, but non-MLS"
" is specified\n", argv[0]);
exit(1);
}
} else {
if (mlspol) {
fprintf(stderr, "%s: non-MLS policy, but MLS"
" is specified\n", argv[0]);
exit(1);
}
}
if (policydbp->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
if (policyvers > policydbp->policyvers) {
fprintf(stderr, "Binary policies with version <= %u cannot be upgraded\n", POLICYDB_VERSION_PERMISSIVE);
} else if (policyvers) {
policydbp->policyvers = policyvers;
}
} else {
policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
}
} else {
if (conf) {
fprintf(stderr, "Can only generate policy.conf from binary policy\n");
exit(1);
}
if (policydb_init(&parse_policy))
exit(1);
/* We build this as a base policy first since that is all the parser understands */
parse_policy.policy_type = POLICY_BASE;
policydb_set_target_platform(&parse_policy, target);
/* Let sepol know if we are dealing with MLS support */
parse_policy.mls = mlspol;
parse_policy.handle_unknown = handle_unknown;
policydbp = &parse_policy;
if (read_source_policy(policydbp, file, "checkpolicy") < 0)
exit(1);
if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
exit(1);
/* Linking takes care of optional avrule blocks */
if (link_modules(NULL, policydbp, NULL, 0, 0)) {
fprintf(stderr, "Error while resolving optionals\n");
exit(1);
}
if (!cil) {
if (policydb_init(&policydb)) {
fprintf(stderr, "%s: policydb_init failed\n", argv[0]);
exit(1);
}
if (expand_module(NULL, policydbp, &policydb, 0, 1)) {
fprintf(stderr, "Error while expanding policy\n");
exit(1);
}
policydb_destroy(policydbp);
policydbp = &policydb;
}
policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
}
if (policydb_load_isids(&policydb, &sidtab))
exit(1);
if (optimize && policydbp->policy_type == POLICY_KERN) {
ret = policydb_optimize(policydbp);
if (ret) {
fprintf(stderr, "%s: error optimizing policy\n", argv[0]);
exit(1);
}
}
if (outfile) {
if (!strcmp(outfile, "-")) {
outfp = stdout;
outfile = "<STDOUT>";
} else {
outfp = fopen(outfile, "w");
if (!outfp) {
perror(outfile);
exit(1);
}
}
if (!cil) {
if (!conf) {
policydb.policy_type = POLICY_KERN;
policy_file_init(&pf);
pf.type = PF_USE_STDIO;
pf.fp = outfp;
if (sort) {
ret = policydb_sort_ocontexts(&policydb);
if (ret) {
fprintf(stderr, "%s: error sorting ocontexts\n",
argv[0]);
exit(1);
}
}
ret = policydb_write(&policydb, &pf);
} else {
ret = sepol_kernel_policydb_to_conf(outfp, policydbp);
}
if (ret) {
fprintf(stderr, "%s: error writing %s\n",
argv[0], outfile);
exit(1);
}
} else {
if (binary) {
ret = sepol_kernel_policydb_to_cil(outfp, policydbp);
} else {
ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
}
if (ret) {
fprintf(stderr, "%s: error writing %s\n", argv[0], outfile);
exit(1);
}
}
if (outfp != stdout) {
fclose(outfp);
}
} else if (cil) {
fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]);
exit(1);
}
if (!debug) {
policydb_destroy(&policydb);
sepol_sidtab_destroy(&sidtab);
exit(0);
}
menu:
printf("\nSelect an option:\n");
printf("0) Call compute_access_vector\n");
printf("1) Call sid_to_context\n");
printf("2) Call context_to_sid\n");
printf("3) Call transition_sid\n");
printf("4) Call member_sid\n");
printf("5) Call change_sid\n");
printf("6) Call list_sids\n");
printf("7) Call load_policy\n");
printf("8) Call fs_sid\n");
printf("9) Call port_sid\n");
printf("a) Call netif_sid\n");
printf("b) Call node_sid\n");
printf("c) Call fs_use\n");
printf("d) Call genfs_sid\n");
printf("e) Call get_user_sids\n");
printf("f) display conditional bools\n");
printf("g) display conditional expressions\n");
printf("h) change a boolean value\n");
printf("i) display constraint expressions\n");
printf("j) display validatetrans expressions\n");
printf("k) Call ibpkey_sid\n");
printf("l) Call ibendport_sid\n");
#ifdef EQUIVTYPES
printf("z) Show equivalent types\n");
#endif
printf("m) Show menu again\n");
printf("q) Exit\n");
while (1) {
printf("\nChoose: ");
FGETS(ans, sizeof(ans), stdin);
switch (ans[0]) {
case '0':
printf("source sid? ");
FGETS(ans, sizeof(ans), stdin);
ssid = atoi(ans);
printf("target sid? ");
FGETS(ans, sizeof(ans), stdin);
tsid = atoi(ans);
printf("target class? ");
FGETS(ans, sizeof(ans), stdin);
if (isdigit(ans[0])) {
tclass = atoi(ans);
if (!tclass
|| tclass > policydb.p_classes.nprim) {
printf("\nNo such class.\n");
break;
}
cladatum =
policydb.class_val_to_struct[tclass - 1];
} else {
ans[strlen(ans) - 1] = 0;
cladatum =
(class_datum_t *) hashtab_search(policydb.
p_classes.
table,
ans);
if (!cladatum) {
printf("\nNo such class\n");
break;
}
tclass = cladatum->s.value;
}
if (!cladatum->comdatum && !cladatum->permissions.nprim) {
printf
("\nNo access vector definition for that class\n");
break;
}
ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
switch (ret) {
case 0:
printf("\nallowed {");
for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
if (avd.allowed & (1 << (i - 1))) {
v.val = i;
ret =
hashtab_map(cladatum->
permissions.
table,
find_perm, &v);
if (!ret && cladatum->comdatum) {
ret =
hashtab_map
(cladatum->
comdatum->
permissions.table,
find_perm, &v);
}
if (ret)
printf(" %s", v.name);
}
}
printf(" }\n");
break;
case -EINVAL:
printf("\ninvalid sid\n");
break;
default:
printf("return code 0x%x\n", ret);
}
break;
case '1':
printf("sid? ");
FGETS(ans, sizeof(ans), stdin);
ssid = atoi(ans);
ret = sepol_sid_to_context(ssid,
&scontext, &scontext_len);
switch (ret) {
case 0:
printf("\nscontext %s\n", scontext);
free(scontext);
break;
case -EINVAL:
printf("\ninvalid sid\n");
break;
case -ENOMEM:
printf("\nout of memory\n");
break;
default:
printf("return code 0x%x\n", ret);
}
break;
case '2':
printf("scontext? ");
FGETS(ans, sizeof(ans), stdin);
scontext_len = strlen(ans);
ans[scontext_len - 1] = 0;
ret = sepol_context_to_sid(ans, scontext_len, &ssid);
switch (ret) {
case 0:
printf("\nsid %d\n", ssid);
break;
case -EINVAL:
printf("\ninvalid context\n");
break;
case -ENOMEM:
printf("\nout of memory\n");
break;
default:
printf("return code 0x%x\n", ret);
}
break;
case '3':
case '4':
case '5':
ch = ans[0];
printf("source sid? ");
FGETS(ans, sizeof(ans), stdin);
ssid = atoi(ans);
printf("target sid? ");
FGETS(ans, sizeof(ans), stdin);
tsid = atoi(ans);
printf("object class? ");
FGETS(ans, sizeof(ans), stdin);
if (isdigit(ans[0])) {
tclass = atoi(ans);
if (!tclass
|| tclass > policydb.p_classes.nprim) {
printf("\nNo such class.\n");
break;
}
} else {
ans[strlen(ans) - 1] = 0;
cladatum =
(class_datum_t *) hashtab_search(policydb.
p_classes.
table,
ans);
if (!cladatum) {
printf("\nNo such class\n");
break;
}
tclass = cladatum->s.value;
}
if (ch == '3')
ret =
sepol_transition_sid(ssid, tsid, tclass,
&ssid);
else if (ch == '4')
ret =
sepol_member_sid(ssid, tsid, tclass, &ssid);
else
ret =
sepol_change_sid(ssid, tsid, tclass, &ssid);
switch (ret) {
case 0:
printf("\nsid %d\n", ssid);
break;
case -EINVAL:
printf("\ninvalid sid\n");
break;
case -ENOMEM:
printf("\nout of memory\n");
break;
default:
printf("return code 0x%x\n", ret);
}
break;
case '6':
sepol_sidtab_map(&sidtab, print_sid, 0);
break;
case '7':
printf("pathname? ");
FGETS(ans, sizeof(ans), stdin);
pathlen = strlen(ans);
ans[pathlen - 1] = 0;
fd = open(ans, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Can't open '%s': %s\n",
ans, strerror(errno));
break;
}
if (fstat(fd, &sb) < 0) {
fprintf(stderr, "Can't stat '%s': %s\n",
ans, strerror(errno));
break;
}
map =
mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
fprintf(stderr, "Can't map '%s': %s\n",
ans, strerror(errno));
break;
}
ret = sepol_load_policy(map, sb.st_size);
switch (ret) {
case 0:
printf("\nsuccess\n");
break;
case -EINVAL:
printf("\ninvalid policy\n");
break;
case -ENOMEM:
printf("\nout of memory\n");
break;
default:
printf("return code 0x%x\n", ret);
}
break;
case '8':
printf("fs kdevname? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
sepol_fs_sid(ans, &ssid, &tsid);
printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
break;
case '9':
printf("protocol? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
protocol = IPPROTO_TCP;
else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
protocol = IPPROTO_UDP;
else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
protocol = IPPROTO_DCCP;
else if (!strcmp(ans, "sctp") || !strcmp(ans, "SCTP"))
protocol = IPPROTO_SCTP;
else {
printf("unknown protocol\n");
break;
}
printf("port? ");
FGETS(ans, sizeof(ans), stdin);
port = atoi(ans);
sepol_port_sid(0, 0, protocol, port, &ssid);
printf("sid %d\n", ssid);
break;
case 'a':
printf("netif name? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
sepol_netif_sid(ans, &ssid, &tsid);
printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
break;
case 'b':{
char *p;
int family, len;
struct in_addr addr4;
struct in6_addr addr6;
printf("protocol family? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
if (!strcasecmp(ans, "ipv4"))
family = AF_INET;
else if (!strcasecmp(ans, "ipv6"))
family = AF_INET6;
else {
printf("unknown protocol family\n");
break;
}
printf("node address? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
if (family == AF_INET) {
p = (char *)&addr4;
len = sizeof(addr4);
} else {
p = (char *)&addr6;
len = sizeof(addr6);
}
if (inet_pton(family, ans, p) < 1) {
printf("error parsing address\n");
break;
}
sepol_node_sid(family, p, len, &ssid);
printf("sid %d\n", ssid);
break;
}
case 'c':
printf("fstype? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
sepol_fs_use(ans, &uret, &ssid);
switch (uret) {
case SECURITY_FS_USE_XATTR:
printf("use xattr\n");
break;
case SECURITY_FS_USE_TRANS:
printf("use transition SIDs\n");
break;
case SECURITY_FS_USE_TASK:
printf("use task SIDs\n");
break;
case SECURITY_FS_USE_GENFS:
printf("use genfs\n");
break;
case SECURITY_FS_USE_NONE:
printf("no labeling support\n");
break;
}
printf("sid %d\n", ssid);
break;
case 'd':
printf("fstype? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
fstype = strdup(ans);
printf("path? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
path = strdup(ans);
printf("object class? ");
FGETS(ans, sizeof(ans), stdin);
if (isdigit(ans[0])) {
tclass = atoi(ans);
if (!tclass
|| tclass > policydb.p_classes.nprim) {
printf("\nNo such class.\n");
break;
}
} else {
ans[strlen(ans) - 1] = 0;
cladatum =
(class_datum_t *) hashtab_search(policydb.
p_classes.
table,
ans);
if (!cladatum) {
printf("\nNo such class\n");
break;
}
tclass = cladatum->s.value;
}
sepol_genfs_sid(fstype, path, tclass, &ssid);
printf("sid %d\n", ssid);
free(fstype);
free(path);
break;
case 'e':
printf("from SID? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
ssid = atoi(ans);
printf("username? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
switch (ret) {
case 0:
if (!nel)
printf("\nnone\n");
for (i = 0; i < nel; i++)
print_sid(sids[i], NULL, NULL);
free(sids);
break;
case -ENOMEM:
printf("\nout of memory\n");
break;
case -EINVAL:
printf("\ninvalid argument\n");
break;
default:
printf("\nerror\n");
break;
}
break;
case 'f':
display_bools();
break;
case 'g':
display_cond_expressions();
break;
case 'h':
printf("name? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
name = malloc((strlen(ans) + 1) * sizeof(char));
if (name == NULL) {
fprintf(stderr, "couldn't malloc string.\n");
break;
}
strcpy(name, ans);
printf("state? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
if (atoi(ans))
state = 1;
else
state = 0;
change_bool(name, state);
free(name);
break;
case 'i':
printf("source sid? ");
FGETS(ans, sizeof(ans), stdin);
ssid = atoi(ans);
printf("target sid? ");
FGETS(ans, sizeof(ans), stdin);
tsid = atoi(ans);
printf("target class? ");
FGETS(ans, sizeof(ans), stdin);
if (isdigit(ans[0])) {
tclass = atoi(ans);
if (!tclass
|| tclass > policydb.p_classes.nprim) {
printf("\nNo such class.\n");
break;
}
cladatum =
policydb.class_val_to_struct[tclass - 1];
} else {
ans[strlen(ans) - 1] = 0;
cladatum =
(class_datum_t *) hashtab_search(policydb.
p_classes.
table,
ans);
if (!cladatum) {
printf("\nNo such class\n");
break;
}
tclass = cladatum->s.value;
}
flags = SHOW_GRANTED;
if (sepol_compute_av_reason_buffer(ssid, tsid,
tclass, 0, &avd, &reason,
&reason_buf, flags)) {
printf("\nconstraint error\n");
break;
}
if (reason_buf) {
printf("\nConstraint expressions:\n%s",
reason_buf);
free(reason_buf);
} else {
printf("\nNo constraints found.\n");
}
break;
case 'j':
printf("old sid? ");
FGETS(ans, sizeof(ans), stdin);
oldsid = atoi(ans);
printf("new sid? ");
FGETS(ans, sizeof(ans), stdin);
newsid = atoi(ans);
printf("task sid? ");
FGETS(ans, sizeof(ans), stdin);
tasksid = atoi(ans);
printf("target class? ");
FGETS(ans, sizeof(ans), stdin);
if (isdigit(ans[0])) {
tclass = atoi(ans);
if (!tclass
|| tclass > policydb.p_classes.nprim) {
printf("\nNo such class.\n");
break;
}
cladatum =
policydb.class_val_to_struct[tclass - 1];
} else {
ans[strlen(ans) - 1] = 0;
cladatum =
(class_datum_t *) hashtab_search(policydb.
p_classes.
table,
ans);
if (!cladatum) {
printf("\nNo such class\n");
break;
}
tclass = cladatum->s.value;
}
flags = SHOW_GRANTED;
if (sepol_validate_transition_reason_buffer(oldsid,
newsid, tasksid, tclass,
&reason_buf, flags)) {
printf("\nvalidatetrans error\n");
break;
}
if (reason_buf) {
printf("\nValidatetrans expressions:\n%s",
reason_buf);
free(reason_buf);
} else {
printf(
"\nNo validatetrans expressions found.\n");
}
break;
case 'k':
{
char *p;
struct in6_addr addr6;
uint64_t subnet_prefix;
unsigned int pkey;
printf("subnet prefix? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
p = (char *)&addr6;
if (inet_pton(AF_INET6, ans, p) < 1) {
printf("error parsing subnet prefix\n");
break;
}
memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
printf("pkey? ");
FGETS(ans, sizeof(ans), stdin);
pkey = atoi(ans);
sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
printf("sid %d\n", ssid);
}
break;
case 'l':
printf("device name (eg. mlx4_0)? ");
FGETS(ans, sizeof(ans), stdin);
ans[strlen(ans) - 1] = 0;
name = malloc((strlen(ans) + 1) * sizeof(char));
if (!name) {
fprintf(stderr, "couldn't malloc string.\n");
break;
}
strcpy(name, ans);
printf("port? ");
FGETS(ans, sizeof(ans), stdin);
port = atoi(ans);
sepol_ibendport_sid(name, port, &ssid);
printf("sid %d\n", ssid);
free(name);
break;
#ifdef EQUIVTYPES
case 'z':
identify_equiv_types();
break;
#endif
case 'm':
goto menu;
case 'q':
exit(0);
break;
default:
printf("\nUnknown option %s.\n", ans);
}
}
return 0;
}
/* FLASK */