mirror of
https://github.com/SELinuxProject/selinux
synced 2024-12-24 06:52:12 +00:00
854fdc1ac4
Reduce noise when calling the checkpolicy command line. In Android, this creates unnecessary build noise which we'd like to avoid. https://en.wikipedia.org/wiki/Unix_philosophy Rule of Silence Developers should design programs so that they do not print unnecessary output. This rule aims to allow other programs and developers to pick out the information they need from a program's output without having to parse verbosity. An alternative approach would be to add a -s (silent) option to these tools, or to have the Android build system redirect stdout to /dev/null. Signed-off-by: Nick Kralevich <nnk@google.com>
1283 lines
29 KiB
C
1283 lines
29 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/flask.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;
|
|
|
|
static int handle_unknown = SEPOL_DENY_UNKNOWN;
|
|
static const char *txtfile = "policy.conf";
|
|
static const char *binfile = "policy";
|
|
|
|
unsigned int policyvers = POLICYDB_VERSION_MAX;
|
|
|
|
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] [-t target_platform (selinux,xen)]"
|
|
"[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], *outfile = NULL, *path, *fstype;
|
|
size_t scontext_len, pathlen;
|
|
unsigned int i;
|
|
unsigned int protocol, port;
|
|
unsigned int binary = 0, debug = 0, cil = 0, conf = 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'},
|
|
{"help", no_argument, NULL, 'h'},
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
|
|
while ((ch = getopt_long(argc, argv, "o:t:dbU:MCFVc:h", 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 '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 'h':
|
|
default:
|
|
usage(argv[0]);
|
|
}
|
|
}
|
|
|
|
if (show_version) {
|
|
printf("%d (compatibility range %d-%d)\n", policyvers,
|
|
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);
|
|
}
|
|
}
|
|
} 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;
|
|
}
|
|
}
|
|
|
|
if (policydb_load_isids(&policydb, &sidtab))
|
|
exit(1);
|
|
|
|
if (outfile) {
|
|
outfp = fopen(outfile, "w");
|
|
if (!outfp) {
|
|
perror(outfile);
|
|
exit(1);
|
|
}
|
|
|
|
policydb.policyvers = policyvers;
|
|
|
|
if (!cil) {
|
|
if (!conf) {
|
|
policydb.policy_type = POLICY_KERN;
|
|
|
|
policy_file_init(&pf);
|
|
pf.type = PF_USE_STDIO;
|
|
pf.fp = outfp;
|
|
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 (outfile) {
|
|
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 */
|