3
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
6
/* Updated: Karl MacMillan <kmacmillan@tresys.com>
8
* Added conditional policy language extensions
10
* Updated: James Morris <jmorris@intercode.com.au>
14
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
15
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
16
* This program is free software; you can redistribute it and/or modify
17
* it under the terms of the GNU General Public License as published by
18
* the Free Software Foundation, version 2.
26
* Load and check a policy configuration.
28
* A policy configuration is created in a text format,
29
* and then compiled into a binary format for use by
30
* the security server. By default, checkpolicy reads
31
* the text format. If '-b' is specified, then checkpolicy
32
* reads the binary format instead.
34
* If '-o output_file' is specified, then checkpolicy
35
* writes the binary format version of the configuration
36
* to the specified output file.
38
* If '-d' is specified, then checkpolicy permits the user
39
* to interactively test the security server functions with
40
* the loaded policy configuration.
42
* If '-c' is specified, then the supplied parameter is used to
43
* determine which policy version to use for generating binary
44
* policy. This is for compatibility with older kernels. If any
45
* booleans or conditional rules are thrown away a warning is printed.
51
#include "checkpolicy.h"
52
#include "conditional.h"
55
#include <sys/types.h>
64
extern policydb_t *policydbp;
65
extern queue_t id_queue;
66
extern unsigned int policydb_errors;
67
extern unsigned long policydb_lineno;
68
extern unsigned long source_lineno;
69
extern char source_file[];
70
extern unsigned int pass;
71
extern unsigned int ss_initialized;
73
extern int policydb_write(policydb_t * p, FILE * fp);
76
extern int yyparse(void);
77
extern void yyrestart(FILE *);
79
char *txtfile = "policy.conf";
80
char *binfile = "policy";
82
int policyvers = POLICYDB_VERSION_MAX;
84
int avc_ss_reset(__u32 seqno __attribute__ ((unused)))
89
void usage(char *progname)
91
printf("usage: %s [-b] [-d] [-c policyvers (%d-%d)] [-o output_file] [input_file]\n",
92
progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
96
static int print_sid(security_id_t sid,
97
context_struct_t * context __attribute__ ((unused)), void *data __attribute__ ((unused)))
99
security_context_t scontext;
103
rc = security_sid_to_context(sid, &scontext, &scontext_len);
105
printf("sid %d -> error %d\n", sid, rc);
107
printf("sid %d -> scontext %s\n", sid, scontext);
118
static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
120
struct val_to_name *v = p;
121
perm_datum_t *perdatum;
123
perdatum = (perm_datum_t *) datum;
125
if (v->val == perdatum->value) {
133
static int type_attr_remove(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *p __attribute__ ((unused)))
135
type_datum_t *typdatum;
137
typdatum = (type_datum_t *) datum;
138
if (typdatum->isattr)
144
static int insert_type_rule(avtab_key_t *k, avtab_datum_t *d,
145
struct avtab_node *type_rules)
147
struct avtab_node *p, *c, *n;
149
for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
151
* Find the insertion point, keeping the list
152
* ordered by source type, then target type, then
155
if (k->source_type < c->key.source_type)
157
if (k->source_type == c->key.source_type &&
158
k->target_type < c->key.target_type)
160
if (k->source_type == c->key.source_type &&
161
k->target_type == c->key.target_type &&
162
k->target_class < c->key.target_class)
166
/* Insert the rule */
167
n = malloc(sizeof(struct avtab_node));
169
fprintf(stderr, "out of memory\n");
180
static int create_type_rules(avtab_key_t *k, avtab_datum_t *d, void *args)
182
struct avtab_node *type_rules = args;
184
if (d->specified & AVTAB_ALLOWED) {
186
* Insert the rule into the lists for both
187
* the source type and the target type.
189
if (insert_type_rule(k, d, &type_rules[k->source_type-1])) return -1;
190
if (insert_type_rule(k, d, &type_rules[k->target_type-1])) return -1;
196
static void free_type_rules(struct avtab_node *l)
198
struct avtab_node *tmp;
207
static int identify_equiv_types(void)
209
struct avtab_node *type_rules, *l1, *l2;
213
* Create a list of access vector rules for each type
214
* from the access vector table.
216
type_rules = malloc(sizeof(struct avtab_node)*policydb.p_types.nprim);
218
fprintf(stderr, "out of memory\n");
221
memset(type_rules, 0, sizeof(struct avtab_node)*policydb.p_types.nprim);
222
if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules))
227
* Compare the type lists and identify equivalent types.
229
for (i = 0; i < policydb.p_types.nprim - 1; i++) {
230
if (!type_rules[i].next)
232
for (j = i + 1; j < policydb.p_types.nprim; j++) {
233
for (l1 = type_rules[i].next, l2 = type_rules[j].next; l1 && l2;
234
l1 = l1->next, l2 = l2->next) {
235
if (l2->key.source_type == (j+1)) {
236
if (l1->key.source_type != (i+1))
239
if (l1->key.source_type != l2->key.source_type)
242
if (l2->key.target_type == (j+1)) {
243
if (l1->key.target_type != (i+1))
246
if (l1->key.target_type != l2->key.target_type)
249
if (l1->key.target_class != l2->key.target_class ||
250
l1->datum.allowed != l2->datum.allowed)
255
free_type_rules(type_rules[j].next);
256
type_rules[j].next = NULL;
257
printf("Types %s and %s are equivalent.\n",
258
policydb.p_type_val_to_name[i],
259
policydb.p_type_val_to_name[j]);
261
free_type_rules(type_rules[i].next);
262
type_rules[i].next = NULL;
270
static void cond_check_type_rules_list(cond_av_list_t *list)
272
cond_av_list_t *cur = list;
275
if (cur->node->datum.specified & AVTAB_TYPE) {
276
if (avtab_search(&policydbp->te_avtab, &cur->node->key, AVTAB_TYPE)) {
277
fprintf(stderr, "conditional type rule for (%s, %s : %s) conflicts with entry in base policy; "
278
"conditional rule discarded.\n", policydbp->p_type_val_to_name[cur->node->key.source_type],
279
policydbp->p_type_val_to_name[cur->node->key.target_type],
280
policydbp->p_class_val_to_name[cur->node->key.target_class]);
281
cur->node->parse_context = (void*)0;
283
cur->node->parse_context = (void*)1;
286
cur->node->parse_context = (void*)1;
292
/* check for duplicate type rules - this has to be done after all of
293
* the parsing is finished because the conditional and base type rules
294
* are collected in the same pass */
295
static void cond_check_type_rules(void)
299
for (node = policydbp->cond_list; node != NULL; node = node->next) {
300
cond_check_type_rules_list(node->true_list);
301
cond_check_type_rules_list(node->false_list);
305
extern char *av_to_string(__u32 tclass, access_vector_t av);
307
void check_assertion_helper(unsigned int stype, unsigned int ttype, ebitmap_t *tclasses,
308
access_vector_t *avp, unsigned long line)
311
avtab_datum_t *avdatump;
315
for (k = ebitmap_startbit(tclasses); k < ebitmap_length(tclasses); k++) {
316
if (!ebitmap_get_bit(tclasses, k))
318
avkey.source_type = stype + 1;
319
avkey.target_type = ttype + 1;
320
avkey.target_class = k + 1;
321
avdatump = avtab_search(&policydb.te_avtab, &avkey, AVTAB_AV);
325
if ((avdatump->specified & AVTAB_ALLOWED) &&
326
(avtab_allowed(avdatump) & avp[k])) {
327
fprintf(stderr, "assertion on line %ld violated by allow %s %s:%s {%s };\n", line, policydb.p_type_val_to_name[stype], policydb.p_type_val_to_name[ttype], policydb.p_class_val_to_name[k],
329
avtab_allowed(avdatump) & avp[k]));
335
void check_assertions(void)
337
te_assert_t *a, *tmp;
342
for (i = ebitmap_startbit(&a->stypes); i < ebitmap_length(&a->stypes); i++) {
343
if (!ebitmap_get_bit(&a->stypes, i))
346
check_assertion_helper(i, i, &a->tclasses, a->avp, a->line);
348
for (j = ebitmap_startbit(&a->ttypes); j < ebitmap_length(&a->ttypes); j++) {
349
if (!ebitmap_get_bit(&a->ttypes, j))
351
check_assertion_helper(i, j, &a->tclasses, a->avp, a->line);
356
ebitmap_destroy(&tmp->stypes);
357
ebitmap_destroy(&tmp->ttypes);
358
ebitmap_destroy(&tmp->tclasses);
368
for (i = 0; i < policydbp->p_bools.nprim; i++) {
369
printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
370
policydbp->bool_val_to_struct[i]->state);
375
void display_expr(cond_expr_t *exp)
379
for (cur = exp; cur != NULL; cur = cur->next) {
380
switch (cur->expr_type) {
382
printf("%s ", policydbp->p_bool_val_to_name[cur->bool - 1]);
409
int display_cond_expressions()
413
for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
414
printf("expression: ");
415
display_expr(cur->expr);
416
printf("current state: %d\n", cur->cur_state);
421
int change_bool(char *name, int state)
423
cond_bool_datum_t *bool;
425
bool = hashtab_search(policydbp->p_bools.table, name);
427
printf("Could not find bool %s\n", name);
431
evaluate_conds(policydbp);
435
int main(int argc, char **argv)
437
security_class_t tclass;
438
security_id_t ssid, tsid, *sids;
439
security_context_t scontext;
440
struct av_decision avd;
441
class_datum_t *cladatum;
442
char ans[80 + 1], *file = txtfile, *outfile = NULL, *path, *fstype;
443
size_t scontext_len, pathlen;
445
unsigned int protocol, port;
446
unsigned int binary = 0, debug = 0;
447
struct val_to_name v;
455
int show_version = 0;
458
while ((ch = getopt(argc, argv, "o:dbVc:")) != EOF) {
474
long int n = strtol(optarg, NULL, 10);
476
fprintf(stderr, "Invalid policyvers specified: %s\n", optarg);
480
if (n < POLICYDB_VERSION_MIN || n > POLICYDB_VERSION_MAX) {
481
fprintf(stderr, "policyvers value %ld not in range %d-%d\n",
482
n, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
496
#ifdef CONFIG_SECURITY_SELINUX_MLS
497
printf("%d-mls (compatibility range %d-%d)\n", policyvers, POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
499
printf("%d (compatibility range %d-%d)\n", policyvers, POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
504
if (optind != argc) {
505
file = argv[optind++];
509
printf("%s: loading policy configuration from %s\n", argv[0],
513
fd = open(file, O_RDONLY);
515
fprintf(stderr, "Can't open '%s': %s\n",
516
file, strerror(errno));
519
if (fstat(fd, &sb) < 0) {
520
fprintf(stderr, "Can't stat '%s': %s\n",
521
file, strerror(errno));
524
map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
525
if (map == MAP_FAILED) {
526
fprintf(stderr, "Can't map '%s': %s\n",
527
file, strerror(errno));
530
ret = security_load_policy(map,sb.st_size);
532
fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", argv[0]);
535
policydbp = &policydb;
537
yyin = fopen(file, "r");
539
fprintf(stderr, "%s: unable to open %s\n", argv[0],
544
if (policydb_init(&policydb))
547
id_queue = queue_create();
549
fprintf(stderr, "%s: out of memory\n", argv[0]);
552
policydbp = &policydb;
555
if (yyparse() || policydb_errors) {
556
fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", argv[0]);
561
source_file[0] = '\0';
565
if (yyparse() || policydb_errors) {
566
fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", argv[0]);
569
queue_destroy(id_queue);
571
cond_check_type_rules();
572
cond_optimize_lists(policydb.cond_list);
578
/* remove type attributes */
579
hashtab_map_remove_on_error(policydb.p_types.table,
580
type_attr_remove, 0, 0);
584
if (policydb_load_isids(&policydb, &sidtab))
587
printf("%s: policy configuration loaded\n", argv[0]);
590
printf("%s: writing binary representation (version %d) to %s\n",
591
argv[0], policyvers, outfile);
592
outfp = fopen(outfile, "w");
597
ret = policydb_write(&policydb, outfp);
599
fprintf(stderr, "%s: error writing %s\n",
611
printf("\nSelect an option:\n");
612
printf("0) Call compute_access_vector\n");
613
printf("1) Call sid_to_context\n");
614
printf("2) Call context_to_sid\n");
615
printf("3) Call transition_sid\n");
616
printf("4) Call member_sid\n");
617
printf("5) Call change_sid\n");
618
printf("6) Call list_sids\n");
619
printf("7) Call load_policy\n");
620
printf("8) Call fs_sid\n");
621
printf("9) Call port_sid\n");
622
printf("a) Call netif_sid\n");
623
printf("b) Call node_sid\n");
624
printf("c) Call fs_use\n");
625
printf("d) Call genfs_sid\n");
626
printf("e) Call get_user_sids\n");
627
printf("f) display conditional bools\n");
628
printf("g) display conditional expressions\n");
629
printf("h) change a boolean value\n");
631
printf("z) Show equivalent types\n");
633
printf("m) Show menu again\n");
636
printf("\nChoose: ");
637
fgets(ans, sizeof(ans), stdin);
640
printf("source sid? ");
641
fgets(ans, sizeof(ans), stdin);
644
printf("target sid? ");
645
fgets(ans, sizeof(ans), stdin);
648
printf("target class? ");
649
fgets(ans, sizeof(ans), stdin);
650
if (isdigit(ans[0])) {
652
if (!tclass || tclass > policydb.p_classes.nprim) {
653
printf("\nNo such class.\n");
656
cladatum = policydb.class_val_to_struct[tclass - 1];
658
ans[strlen(ans) - 1] = 0;
659
cladatum = (class_datum_t *) hashtab_search(policydb.p_classes.table,
662
printf("\nNo such class\n");
665
tclass = cladatum->value;
668
if (!cladatum->comdatum && !cladatum->permissions.nprim) {
669
printf("\nNo access vector definition for that class\n");
672
ret = security_compute_av(ssid, tsid, tclass, 0,
676
printf("\nallowed {");
677
for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
678
if (avd.allowed & (1 << (i - 1))) {
680
ret = hashtab_map(cladatum->permissions.table,
682
if (!ret && cladatum->comdatum) {
683
ret = hashtab_map(cladatum->comdatum->permissions.table,
687
printf(" %s", v.name);
693
printf("\ninvalid sid\n");
696
printf("return code 0x%x\n", ret);
701
fgets(ans, sizeof(ans), stdin);
703
ret = security_sid_to_context(ssid,
704
&scontext, &scontext_len);
707
printf("\nscontext %s\n", scontext);
711
printf("\ninvalid sid\n");
714
printf("\nout of memory\n");
717
printf("return code 0x%x\n", ret);
721
printf("scontext? ");
722
fgets(ans, sizeof(ans), stdin);
723
scontext_len = strlen(ans);
724
ans[scontext_len - 1] = 0;
725
ret = security_context_to_sid(ans, scontext_len,
729
printf("\nsid %d\n", ssid);
732
printf("\ninvalid context\n");
735
printf("\nout of memory\n");
738
printf("return code 0x%x\n", ret);
746
printf("source sid? ");
747
fgets(ans, sizeof(ans), stdin);
749
printf("target sid? ");
750
fgets(ans, sizeof(ans), stdin);
753
printf("object class? ");
754
fgets(ans, sizeof(ans), stdin);
755
if (isdigit(ans[0])) {
757
if (!tclass || tclass > policydb.p_classes.nprim) {
758
printf("\nNo such class.\n");
762
ans[strlen(ans) - 1] = 0;
763
cladatum = (class_datum_t *) hashtab_search(policydb.p_classes.table,
766
printf("\nNo such class\n");
769
tclass = cladatum->value;
773
ret = security_transition_sid(ssid, tsid, tclass, &ssid);
775
ret = security_member_sid(ssid, tsid, tclass, &ssid);
777
ret = security_change_sid(ssid, tsid, tclass, &ssid);
780
printf("\nsid %d\n", ssid);
783
printf("\ninvalid sid\n");
786
printf("\nout of memory\n");
789
printf("return code 0x%x\n", ret);
793
sidtab_map(&sidtab, print_sid, 0);
796
printf("pathname? ");
797
fgets(ans, sizeof(ans), stdin);
798
pathlen = strlen(ans);
799
ans[pathlen - 1] = 0;
800
printf("%s: loading policy configuration from %s\n", argv[0], ans);
801
fd = open(ans, O_RDONLY);
803
fprintf(stderr, "Can't open '%s': %s\n",
804
ans, strerror(errno));
807
if (fstat(fd, &sb) < 0) {
808
fprintf(stderr, "Can't stat '%s': %s\n",
809
ans, strerror(errno));
812
map = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
813
if (map == MAP_FAILED) {
814
fprintf(stderr, "Can't map '%s': %s\n",
815
ans, strerror(errno));
818
ret = security_load_policy(map,sb.st_size);
821
printf("\nsuccess\n");
824
printf("\ninvalid policy\n");
827
printf("\nout of memory\n");
830
printf("return code 0x%x\n", ret);
834
printf("fs kdevname? ");
835
fgets(ans, sizeof(ans), stdin);
836
ans[strlen(ans) - 1] = 0;
837
security_fs_sid(ans, &ssid, &tsid);
838
printf("fs_sid %d default_file_sid %d\n",
842
printf("protocol? ");
843
fgets(ans, sizeof(ans), stdin);
844
ans[strlen(ans) - 1] = 0;
845
if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
846
protocol = IPPROTO_TCP;
847
else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
848
protocol = IPPROTO_UDP;
850
printf("unknown protocol\n");
854
fgets(ans, sizeof(ans), stdin);
856
security_port_sid(0, 0, protocol, port, &ssid);
857
printf("sid %d\n", ssid);
860
printf("netif name? ");
861
fgets(ans, sizeof(ans), stdin);
862
ans[strlen(ans) - 1] = 0;
863
security_netif_sid(ans, &ssid, &tsid);
864
printf("if_sid %d default_msg_sid %d\n",
870
struct in_addr addr4;
871
struct in6_addr addr6;
873
printf("protocol family? ");
874
fgets(ans, sizeof(ans), stdin);
875
ans[strlen(ans) - 1] = 0;
876
if (!strcasecmp(ans, "ipv4"))
878
else if (!strcasecmp(ans, "ipv6"))
881
printf("unknown protocol family\n");
885
printf("node address? ");
886
fgets(ans, sizeof(ans), stdin);
887
ans[strlen(ans) - 1] = 0;
889
if (family == AF_INET) {
897
if (inet_pton(family, ans, p) < 1) {
898
printf("error parsing address\n");
902
security_node_sid(family, p, len, &ssid);
903
printf("sid %d\n", ssid);
908
fgets(ans, sizeof(ans), stdin);
909
ans[strlen(ans) - 1] = 0;
910
security_fs_use(ans, &ret, &ssid);
912
case SECURITY_FS_USE_XATTR:
913
printf("use xattr\n");
915
case SECURITY_FS_USE_TRANS:
916
printf("use transition SIDs\n");
918
case SECURITY_FS_USE_TASK:
919
printf("use task SIDs\n");
921
case SECURITY_FS_USE_GENFS:
922
printf("use genfs\n");
924
case SECURITY_FS_USE_NONE:
925
printf("no labeling support\n");
928
printf("sid %d\n", ssid);
932
fgets(ans, sizeof(ans), stdin);
933
ans[strlen(ans) - 1] = 0;
934
fstype = strdup(ans);
936
fgets(ans, sizeof(ans), stdin);
937
ans[strlen(ans) - 1] = 0;
939
printf("object class? ");
940
fgets(ans, sizeof(ans), stdin);
941
if (isdigit(ans[0])) {
943
if (!tclass || tclass > policydb.p_classes.nprim) {
944
printf("\nNo such class.\n");
948
ans[strlen(ans) - 1] = 0;
949
cladatum = (class_datum_t *) hashtab_search(policydb.p_classes.table,
952
printf("\nNo such class\n");
955
tclass = cladatum->value;
957
security_genfs_sid(fstype, path, tclass, &ssid);
958
printf("sid %d\n", ssid);
963
printf("from SID? ");
964
fgets(ans, sizeof(ans), stdin);
965
ans[strlen(ans) - 1] = 0;
968
printf("username? ");
969
fgets(ans, sizeof(ans), stdin);
970
ans[strlen(ans) - 1] = 0;
972
ret = security_get_user_sids(ssid, ans, &sids, &nel);
977
for (i = 0; i < nel; i++)
978
print_sid(sids[i],NULL,NULL);
982
printf("\nout of memory\n");
985
printf("\ninvalid argument\n");
996
display_cond_expressions();
1000
fgets(ans, sizeof(ans), stdin);
1001
ans[strlen(ans) - 1] = 0;
1003
name = malloc((strlen(ans) + 1) * sizeof(char));
1005
fprintf(stderr, "couldn't malloc string.\n");
1012
fgets(ans, sizeof(ans), stdin);
1013
ans[strlen(ans) - 1] = 0;
1020
change_bool(name, state);
1025
identify_equiv_types();
1034
printf("\nUnknown option %s.\n", ans);