blob: ad75d16d82d03efdfcc0a62f31bd76e86a6bb487 [file] [log] [blame]
Geremy Condra01aaeb62013-08-22 18:23:37 -07001/*
2 * This was derived from public domain works with updates to
3 * work with more modern SELinux libraries.
4 *
5 * It is released into the public domain.
6 *
7 */
8
9#include <getopt.h>
10#include <unistd.h>
11#include <stdlib.h>
12#include <sys/mman.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <sepol/policydb/policydb.h>
18#include <sepol/policydb/services.h>
Stephen Smalley640991b2013-09-12 16:19:30 -040019#include <sepol/policydb/expand.h>
Geremy Condra01aaeb62013-08-22 18:23:37 -070020
21#define EQUALS 0
22#define NOT 1
23#define ANY 2
24
25void usage(char *arg0) {
26 fprintf(stderr, "%s -s <source> -t <target> -c <class> -p <perm> -P <policy file>\n", arg0);
27 exit(1);
28}
29
30void *cmalloc(size_t s) {
31 void *t = malloc(s);
32 if (t == NULL) {
33 fprintf(stderr, "Out of memory\n");
34 exit(1);
35 }
36 return t;
37}
38
39int parse_ops(char **arg) {
40 switch (*arg[0]) {
41 case '-':
42 *arg = *arg + 1;
43 return NOT;
44 case '*':
45 return ANY;
46 default:
47 return EQUALS;
48 }
49}
50
51int check(int op, uint16_t arg1, uint16_t arg2) {
52 switch (op) {
53 case EQUALS:
54 return arg1 == arg2;
55 case NOT:
56 return arg1 != arg2;
57 case ANY:
58 return 1;
59 default:
60 fprintf(stderr, "Bad op while checking!");
61 return 2;
62 }
63}
64
65int check_perm(avtab_ptr_t current, perm_datum_t *perm) {
66 uint16_t perm_bitmask = 1U << (perm->s.value - 1);
67 return (current->datum.data & perm_bitmask) != 0;
68}
69
Stephen Smalley640991b2013-09-12 16:19:30 -040070
71int expand_and_check(int s_op, uint32_t source_type,
72 int t_op, uint32_t target_type,
73 int c_op, uint32_t target_class,
74 perm_datum_t *perm, policydb_t *policy, avtab_t *avtab) {
75 avtab_t exp_avtab;
76 avtab_ptr_t cur;
77 unsigned int i;
78 int match;
79
80 if (avtab_init(&exp_avtab)) {
81 fputs("out of memory\n", stderr);
82 return -1;
83 }
84
85 if (expand_avtab(policy, avtab, &exp_avtab)) {
86 fputs("out of memory\n", stderr);
87 avtab_destroy(&exp_avtab);
88 return -1;
89 }
90
91 for (i = 0; i < exp_avtab.nslot; i++) {
92 for (cur = exp_avtab.htable[i]; cur; cur = cur->next) {
93 match = 1;
94 match &= check(s_op, source_type, cur->key.source_type);
95 match &= check(t_op, target_type, cur->key.target_type);
96 match &= check(c_op, target_class, cur->key.target_class);
97 match &= check_perm(cur, perm);
98 if (match) {
99 avtab_destroy(&exp_avtab);
100 return 1;
101 }
102 }
103 }
104
105 avtab_destroy(&exp_avtab);
106 return 0;
107}
108
Geremy Condra01aaeb62013-08-22 18:23:37 -0700109/*
110 * Checks to see if a rule matching the given arguments already exists.
111 *
112 * The format for the arguments is as follows:
113 *
114 * - A bare string is treated as a literal and will be matched by equality.
115 * - A string starting with "-" will be matched by inequality.
116 * - A string starting with "*" will be treated as a wildcard.
117 *
118 * The return codes for this function are as follows:
119 *
120 * - 0 indicates a successful return without a match
121 * - 1 indicates a successful return with a match
122 * - -1 indicates an error
123 */
124int check_rule(char *s, char *t, char *c, char *p, policydb_t *policy) {
125 type_datum_t *src = NULL;
126 type_datum_t *tgt = NULL;
127 class_datum_t *cls = NULL;
128 perm_datum_t *perm = NULL;
129 int s_op = parse_ops(&s);
130 int t_op = parse_ops(&t);
131 int c_op = parse_ops(&c);
132 int p_op = parse_ops(&p);
133 avtab_key_t key;
Geremy Condra01aaeb62013-08-22 18:23:37 -0700134 int match;
135
136 if (s_op != ANY) {
137 src = hashtab_search(policy->p_types.table, s);
138 if (src == NULL) {
139 fprintf(stderr, "source type %s does not exist\n", s);
140 return -1;
141 }
142 }
143 if (t_op != ANY) {
144 tgt = hashtab_search(policy->p_types.table, t);
145 if (tgt == NULL) {
146 fprintf(stderr, "target type %s does not exist\n", t);
147 return -1;
148 }
149 }
150 if (c_op != ANY) {
151 cls = hashtab_search(policy->p_classes.table, c);
152 if (cls == NULL) {
153 fprintf(stderr, "class %s does not exist\n", c);
154 return -1;
155 }
156 }
157 if (p_op != ANY) {
158 perm = hashtab_search(cls->permissions.table, p);
159 if (perm == NULL) {
160 if (cls->comdatum == NULL) {
161 fprintf(stderr, "perm %s does not exist in class %s\n", p, c);
162 return -1;
163 }
164 perm = hashtab_search(cls->comdatum->permissions.table, p);
165 if (perm == NULL) {
166 fprintf(stderr, "perm %s does not exist in class %s\n", p, c);
167 return -1;
168 }
169 }
170 }
171
172 if (s_op != ANY)
173 key.source_type = src->s.value;
174 if (t_op != ANY)
175 key.target_type = tgt->s.value;
176 if (c_op != ANY)
177 key.target_class = cls->s.value;
178
Stephen Smalley640991b2013-09-12 16:19:30 -0400179 /* Check unconditional rules after attribute expansion. */
180 match = expand_and_check(s_op, key.source_type,
181 t_op, key.target_type,
182 c_op, key.target_class,
183 perm, policy, &policy->te_avtab);
184 if (match)
185 return match;
Geremy Condra01aaeb62013-08-22 18:23:37 -0700186
Stephen Smalley640991b2013-09-12 16:19:30 -0400187 /* Check conditional rules after attribute expansion. */
188 return expand_and_check(s_op, key.source_type,
189 t_op, key.target_type,
190 c_op, key.target_class,
191 perm, policy, &policy->te_cond_avtab);
Geremy Condra01aaeb62013-08-22 18:23:37 -0700192}
193
194int load_policy(char *filename, policydb_t *policydb, struct policy_file *pf) {
195 int fd;
196 struct stat sb;
197 void *map;
198 int ret;
199
200 fd = open(filename, O_RDONLY);
201 if (fd < 0) {
202 fprintf(stderr, "Can't open '%s': %s\n", filename, strerror(errno));
203 return 1;
204 }
205 if (fstat(fd, &sb) < 0) {
206 fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno));
207 close(fd);
208 return 1;
209 }
210 map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
211 if (map == MAP_FAILED) {
212 fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno));
213 close(fd);
214 return 1;
215 }
216
217 policy_file_init(pf);
218 pf->type = PF_USE_MEMORY;
219 pf->data = map;
220 pf->len = sb.st_size;
221 if (policydb_init(policydb)) {
222 fprintf(stderr, "Could not initialize policydb!\n");
223 close(fd);
224 munmap(map, sb.st_size);
225 return 1;
226 }
227 ret = policydb_read(policydb, pf, 0);
228 if (ret) {
229 fprintf(stderr, "error(s) encountered while parsing configuration\n");
230 close(fd);
231 munmap(map, sb.st_size);
232 return 1;
233 }
234
235 return 0;
236}
237
238
239int main(int argc, char **argv)
240{
241 char *policy = NULL, *source = NULL, *target = NULL, *class = NULL, *perm = NULL;
242 policydb_t policydb;
243 struct policy_file pf;
244 sidtab_t sidtab;
245 char ch;
246 int match = 1;
247
248 struct option long_options[] = {
249 {"source", required_argument, NULL, 's'},
250 {"target", required_argument, NULL, 't'},
251 {"class", required_argument, NULL, 'c'},
252 {"perm", required_argument, NULL, 'p'},
253 {"policy", required_argument, NULL, 'P'},
254 {NULL, 0, NULL, 0}
255 };
256
257 while ((ch = getopt_long(argc, argv, "s:t:c:p:P:", long_options, NULL)) != -1) {
258 switch (ch) {
259 case 's':
260 source = optarg;
261 break;
262 case 't':
263 target = optarg;
264 break;
265 case 'c':
266 class = optarg;
267 break;
268 case 'p':
269 perm = optarg;
270 break;
271 case 'P':
272 policy = optarg;
273 break;
274 default:
275 usage(argv[0]);
276 }
277 }
278
279 if (!source || !target || !class || !perm || !policy)
280 usage(argv[0]);
281
282 sepol_set_policydb(&policydb);
283 sepol_set_sidtab(&sidtab);
284
285 if (load_policy(policy, &policydb, &pf))
286 goto out;
287
Geremy Condra01aaeb62013-08-22 18:23:37 -0700288 match = check_rule(source, target, class, perm, &policydb);
289 if (match < 0) {
290 fprintf(stderr, "Error checking rules!\n");
291 goto out;
292 } else if (match > 0) {
293 printf("Match found!\n");
294 goto out;
295 }
296
297 match = 0;
298
299out:
300 policydb_destroy(&policydb);
301 return match;
302}