debuggers.hg

view tools/security/secpol_tool.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 9fad5e5e2fc1
children 74fb7eaa6597
line source
1 /****************************************************************
2 * secpol_tool.c
3 *
4 * Copyright (C) 2005 IBM Corporation
5 *
6 * Authors:
7 * Reiner Sailer <sailer@watson.ibm.com>
8 * Stefan Berger <stefanb@watson.ibm.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation, version 2 of the
13 * License.
14 *
15 * sHype policy management tool. This code runs in a domain and
16 * manages the Xen security policy by interacting with the
17 * Xen access control module via the privcmd device,
18 * which is translated into a acm_op hypercall into Xen.
19 *
20 * indent -i4 -kr -nut
21 */
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include <sys/mman.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stdlib.h>
33 #include <sys/ioctl.h>
34 #include <string.h>
35 #include <netinet/in.h>
36 #include <stdint.h>
37 #include <xen/xsm/acm.h>
38 #include <xen/xsm/acm_ops.h>
40 #include <xenctrl.h>
42 #define PERROR(_m, _a...) \
43 fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
44 errno, strerror(errno))
46 void usage(char *progname)
47 {
48 printf("Usage: %s ACTION\n"
49 "ACTION is one of:\n"
50 "\t getpolicy\n"
51 "\t dumpstats\n"
52 "\t loadpolicy <binary policy file>\n"
53 "\t dumppolicy <binary policy file> [Dom-0 ssidref]\n",
54 progname);
55 exit(-1);
56 }
58 /*************************** DUMPS *******************************/
60 void acm_dump_chinesewall_buffer(void *buf, int buflen, uint16_t chwall_ref)
61 {
63 struct acm_chwall_policy_buffer *cwbuf =
64 (struct acm_chwall_policy_buffer *) buf;
65 domaintype_t *ssids, *conflicts, *running_types, *conflict_aggregate;
66 int i, j;
69 if (htonl(cwbuf->policy_code) != ACM_CHINESE_WALL_POLICY) {
70 printf("CHINESE WALL POLICY CODE not found ERROR!!\n");
71 return;
72 }
73 printf("\n\nChinese Wall policy:\n");
74 printf("====================\n");
75 printf("Policy version= %x.\n", ntohl(cwbuf->policy_version));
76 printf("Max Types = %x.\n", ntohl(cwbuf->chwall_max_types));
77 printf("Max Ssidrefs = %x.\n", ntohl(cwbuf->chwall_max_ssidrefs));
78 printf("Max ConfSets = %x.\n", ntohl(cwbuf->chwall_max_conflictsets));
79 printf("Ssidrefs Off = %x.\n", ntohl(cwbuf->chwall_ssid_offset));
80 printf("Conflicts Off = %x.\n",
81 ntohl(cwbuf->chwall_conflict_sets_offset));
82 printf("Runing T. Off = %x.\n",
83 ntohl(cwbuf->chwall_running_types_offset));
84 printf("C. Agg. Off = %x.\n",
85 ntohl(cwbuf->chwall_conflict_aggregate_offset));
86 printf("\nSSID To CHWALL-Type matrix:\n");
88 ssids = (domaintype_t *) (buf + ntohl(cwbuf->chwall_ssid_offset));
89 for (i = 0; i < ntohl(cwbuf->chwall_max_ssidrefs); i++) {
90 printf("\n ssidref%2x: ", i);
91 for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++)
92 printf("%02x ",
93 ntohs(ssids[i * ntohl(cwbuf->chwall_max_types) + j]));
94 if (i == chwall_ref)
95 printf(" <-- Domain-0");
96 }
97 printf("\n\nConfict Sets:\n");
98 conflicts =
99 (domaintype_t *) (buf + ntohl(cwbuf->chwall_conflict_sets_offset));
100 for (i = 0; i < ntohl(cwbuf->chwall_max_conflictsets); i++) {
101 printf("\n c-set%2x: ", i);
102 for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++)
103 printf("%02x ",
104 ntohs(conflicts
105 [i * ntohl(cwbuf->chwall_max_types) + j]));
106 }
107 printf("\n");
109 printf("\nRunning\nTypes: ");
110 if (ntohl(cwbuf->chwall_running_types_offset)) {
111 running_types =
112 (domaintype_t *) (buf +
113 ntohl(cwbuf->chwall_running_types_offset));
114 for (i = 0; i < ntohl(cwbuf->chwall_max_types); i++) {
115 printf("%02x ", ntohs(running_types[i]));
116 }
117 printf("\n");
118 } else {
119 printf("Not Reported!\n");
120 }
121 printf("\nConflict\nAggregate Set: ");
122 if (ntohl(cwbuf->chwall_conflict_aggregate_offset)) {
123 conflict_aggregate =
124 (domaintype_t *) (buf +
125 ntohl(cwbuf->
126 chwall_conflict_aggregate_offset));
127 for (i = 0; i < ntohl(cwbuf->chwall_max_types); i++) {
128 printf("%02x ", ntohs(conflict_aggregate[i]));
129 }
130 printf("\n\n");
131 } else {
132 printf("Not Reported!\n");
133 }
134 }
136 void acm_dump_ste_buffer(void *buf, int buflen, uint16_t ste_ref)
137 {
139 struct acm_ste_policy_buffer *stebuf =
140 (struct acm_ste_policy_buffer *) buf;
141 domaintype_t *ssids;
142 int i, j;
145 if (ntohl(stebuf->policy_code) != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
146 printf("SIMPLE TYPE ENFORCEMENT POLICY CODE not found ERROR!!\n");
147 return;
148 }
149 printf("\nSimple Type Enforcement policy:\n");
150 printf("===============================\n");
151 printf("Policy version= %x.\n", ntohl(stebuf->policy_version));
152 printf("Max Types = %x.\n", ntohl(stebuf->ste_max_types));
153 printf("Max Ssidrefs = %x.\n", ntohl(stebuf->ste_max_ssidrefs));
154 printf("Ssidrefs Off = %x.\n", ntohl(stebuf->ste_ssid_offset));
155 printf("\nSSID To STE-Type matrix:\n");
157 ssids = (domaintype_t *) (buf + ntohl(stebuf->ste_ssid_offset));
158 for (i = 0; i < ntohl(stebuf->ste_max_ssidrefs); i++) {
159 printf("\n ssidref%2x: ", i);
160 for (j = 0; j < ntohl(stebuf->ste_max_types); j++)
161 printf("%02x ",
162 ntohs(ssids[i * ntohl(stebuf->ste_max_types) + j]));
163 if (i == ste_ref)
164 printf(" <-- Domain-0");
165 }
166 printf("\n\n");
167 }
169 void acm_dump_policy_buffer(void *buf, int buflen,
170 uint16_t chwall_ref, uint16_t ste_ref)
171 {
172 struct acm_policy_buffer *pol = (struct acm_policy_buffer *) buf;
173 char *policy_reference_name =
174 (buf + ntohl(pol->policy_reference_offset) +
175 sizeof(struct acm_policy_reference_buffer));
176 printf("\nPolicy dump:\n");
177 printf("============\n");
178 printf("POLICY REFERENCE = %s.\n", policy_reference_name);
179 printf("PolicyVer = %x.\n", ntohl(pol->policy_version));
180 printf("XML Vers. = %d.%d\n",
181 ntohl(pol->xml_pol_version.major),
182 ntohl(pol->xml_pol_version.minor));
183 printf("Magic = %x.\n", ntohl(pol->magic));
184 printf("Len = %x.\n", ntohl(pol->len));
185 printf("Primary = %s (c=%x, off=%x).\n",
186 ACM_POLICY_NAME(ntohl(pol->primary_policy_code)),
187 ntohl(pol->primary_policy_code),
188 ntohl(pol->primary_buffer_offset));
189 printf("Secondary = %s (c=%x, off=%x).\n",
190 ACM_POLICY_NAME(ntohl(pol->secondary_policy_code)),
191 ntohl(pol->secondary_policy_code),
192 ntohl(pol->secondary_buffer_offset));
193 switch (ntohl(pol->primary_policy_code)) {
194 case ACM_CHINESE_WALL_POLICY:
195 acm_dump_chinesewall_buffer(buf + ntohl(pol->primary_buffer_offset),
196 ntohl(pol->len) -
197 ntohl(pol->primary_buffer_offset),
198 chwall_ref);
199 break;
201 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
202 acm_dump_ste_buffer(buf + ntohl(pol->primary_buffer_offset),
203 ntohl(pol->len) -
204 ntohl(pol->primary_buffer_offset),
205 ste_ref);
206 break;
208 case ACM_NULL_POLICY:
209 printf("Primary policy is NULL Policy (n/a).\n");
210 break;
212 default:
213 printf("UNKNOWN POLICY!\n");
214 }
216 switch (ntohl(pol->secondary_policy_code)) {
217 case ACM_CHINESE_WALL_POLICY:
218 acm_dump_chinesewall_buffer(buf + ntohl(pol->secondary_buffer_offset),
219 ntohl(pol->len) -
220 ntohl(pol->secondary_buffer_offset),
221 chwall_ref);
222 break;
224 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
225 acm_dump_ste_buffer(buf + ntohl(pol->secondary_buffer_offset),
226 ntohl(pol->len) -
227 ntohl(pol->secondary_buffer_offset),
228 ste_ref);
229 break;
231 case ACM_NULL_POLICY:
232 printf("Secondary policy is NULL Policy (n/a).\n");
233 break;
235 default:
236 printf("UNKNOWN POLICY!\n");
237 }
238 }
240 /************************** get dom0 ssidref *****************************/
241 int acm_get_ssidref(xc_interface *xc_handle, int domid, uint16_t *chwall_ref,
242 uint16_t *ste_ref)
243 {
244 int ret;
245 DECLARE_HYPERCALL_BUFFER(struct acm_ssid_buffer, ssid);
246 size_t ssid_buffer_size = 4096;
247 struct acm_getssid getssid;
248 ssid = xc_hypercall_buffer_alloc(xc_handle, ssid, ssid_buffer_size);
249 if ( ssid == NULL )
250 return 1;
251 set_xen_guest_handle(getssid.ssidbuf, ssid);
252 getssid.ssidbuf_size = ssid_buffer_size;
253 getssid.get_ssid_by = ACM_GETBY_domainid;
254 getssid.id.domainid = domid;
255 ret = xc_acm_op(xc_handle, ACMOP_getssid, &getssid, sizeof(getssid));
256 if (ret == 0) {
257 *chwall_ref = ssid->ssidref & 0xffff;
258 *ste_ref = ssid->ssidref >> 16;
259 }
260 xc_hypercall_buffer_free(xc_handle, ssid);
261 return ret;
262 }
264 /******************************* get policy ******************************/
266 int acm_domain_getpolicy(xc_interface *xc_handle)
267 {
268 DECLARE_HYPERCALL_BUFFER(uint8_t, pull_buffer);
269 size_t pull_cache_size = 8192;
270 struct acm_getpolicy getpolicy;
271 int ret;
272 uint16_t chwall_ref, ste_ref;
274 pull_buffer = xc_hypercall_buffer_alloc(xc_handle, pull_buffer, pull_cache_size);
275 if ( pull_buffer == NULL )
276 return -1;
278 memset(pull_buffer, 0x00, pull_cache_size);
279 set_xen_guest_handle(getpolicy.pullcache, pull_buffer);
280 getpolicy.pullcache_size = pull_cache_size;
281 ret = xc_acm_op(xc_handle, ACMOP_getpolicy, &getpolicy, sizeof(getpolicy));
282 if (ret >= 0) {
283 ret = acm_get_ssidref(xc_handle, 0, &chwall_ref, &ste_ref);
284 }
286 if (ret < 0) {
287 printf("ACM operation failed: errno=%d\n", errno);
288 if (errno == EACCES)
289 fprintf(stderr, "ACM operation failed -- need to"
290 " rebuild the user-space tool set?\n");
291 }
293 /* dump policy */
294 acm_dump_policy_buffer(pull_buffer, pull_cache_size,
295 chwall_ref, ste_ref);
297 xc_hypercall_buffer_free(xc_handle, pull_buffer);
299 return ret;
300 }
302 /************************ dump binary policy ******************************/
304 static int load_file(const char *filename,
305 uint8_t **buffer, off_t *len,
306 xc_interface *xc_handle,
307 xc_hypercall_buffer_t *hcall)
308 {
309 struct stat mystat;
310 int ret = 0;
311 int fd;
312 DECLARE_HYPERCALL_BUFFER_ARGUMENT(hcall);
314 if ((ret = stat(filename, &mystat)) != 0) {
315 printf("File %s not found.\n", filename);
316 ret = errno;
317 goto out;
318 }
320 *len = mystat.st_size;
322 if ( hcall == NULL ) {
323 if ((*buffer = malloc(*len)) == NULL) {
324 ret = -ENOMEM;
325 goto out;
326 }
327 } else {
328 if ((*buffer = xc_hypercall_buffer_alloc(xc_handle, hcall, *len)) == NULL) {
329 ret = -ENOMEM;
330 goto out;
331 }
332 }
334 if ((fd = open(filename, O_RDONLY)) <= 0) {
335 ret = -ENOENT;
336 printf("File %s not found.\n", filename);
337 goto free_out;
338 }
340 if (*len == read(fd, *buffer, *len))
341 return 0;
343 free_out:
344 if ( hcall == NULL )
345 free(*buffer);
346 else
347 xc_hypercall_buffer_free(xc_handle, hcall);
348 *buffer = NULL;
349 *len = 0;
350 out:
351 return ret;
352 }
354 static int acm_domain_dumppolicy(const char *filename, uint32_t ssidref)
355 {
356 uint8_t *buffer = NULL;
357 off_t len;
358 int ret = 0;
359 uint16_t chwall_ssidref, ste_ssidref;
361 chwall_ssidref = (ssidref ) & 0xffff;
362 ste_ssidref = (ssidref >> 16) & 0xffff;
364 if ((ret = load_file(filename, &buffer, &len, NULL, NULL)) == 0) {
365 acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref);
366 free(buffer);
367 }
369 return ret;
370 }
372 /************************ load binary policy ******************************/
374 int acm_domain_loadpolicy(xc_interface *xc_handle, const char *filename)
375 {
376 int ret;
377 off_t len;
378 DECLARE_HYPERCALL_BUFFER(uint8_t, buffer);
379 uint16_t chwall_ssidref, ste_ssidref;
380 struct acm_setpolicy setpolicy;
382 ret = load_file(filename, &buffer, &len, xc_handle, HYPERCALL_BUFFER(buffer));
383 if (ret != 0)
384 goto out;
386 ret = acm_get_ssidref(xc_handle, 0, &chwall_ssidref, &ste_ssidref);
387 if (ret < 0)
388 goto free_out;
390 /* dump it and then push it down into xen/acm */
391 acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref);
392 set_xen_guest_handle(setpolicy.pushcache, buffer);
393 setpolicy.pushcache_size = len;
394 ret = xc_acm_op(xc_handle, ACMOP_setpolicy, &setpolicy, sizeof(setpolicy));
396 if (ret) {
397 printf("ERROR setting policy.\n");
398 } else {
399 printf("Successfully changed policy.\n");
400 }
402 free_out:
403 xc_hypercall_buffer_free(xc_handle, buffer);
404 out:
405 return ret;
406 }
408 /************************ dump hook statistics ******************************/
409 void dump_ste_stats(struct acm_ste_stats_buffer *ste_stats)
410 {
411 printf("STE-Policy Security Hook Statistics:\n");
412 printf("ste: event_channel eval_count = %d\n",
413 ntohl(ste_stats->ec_eval_count));
414 printf("ste: event_channel denied_count = %d\n",
415 ntohl(ste_stats->ec_denied_count));
416 printf("ste: event_channel cache_hit_count = %d\n",
417 ntohl(ste_stats->ec_cachehit_count));
418 printf("ste:\n");
419 printf("ste: grant_table eval_count = %d\n",
420 ntohl(ste_stats->gt_eval_count));
421 printf("ste: grant_table denied_count = %d\n",
422 ntohl(ste_stats->gt_denied_count));
423 printf("ste: grant_table cache_hit_count = %d\n",
424 ntohl(ste_stats->gt_cachehit_count));
425 }
427 int acm_domain_dumpstats(xc_interface *xc_handle)
428 {
429 DECLARE_HYPERCALL_BUFFER(uint8_t, stats_buffer);
430 size_t pull_stats_size = 8192;
431 struct acm_dumpstats dumpstats;
432 int ret;
433 struct acm_stats_buffer *stats;
435 stats_buffer = xc_hypercall_buffer_alloc(xc_handle, stats_buffer, pull_stats_size);
436 if ( stats_buffer == NULL )
437 return -1;
439 memset(stats_buffer, 0x00, pull_stats_size);
440 set_xen_guest_handle(dumpstats.pullcache, stats_buffer);
441 dumpstats.pullcache_size = pull_stats_size;
442 ret = xc_acm_op(xc_handle, ACMOP_dumpstats, &dumpstats, sizeof(dumpstats));
444 if (ret < 0) {
445 printf
446 ("ERROR dumping policy stats. Try 'xm dmesg' to see details.\n");
447 xc_hypercall_buffer_free(xc_handle, stats_buffer);
448 return ret;
449 }
450 stats = (struct acm_stats_buffer *) stats_buffer;
452 printf("\nPolicy dump:\n");
453 printf("============\n");
454 printf("Magic = %x.\n", ntohl(stats->magic));
455 printf("Len = %x.\n", ntohl(stats->len));
457 switch (ntohl(stats->primary_policy_code)) {
458 case ACM_NULL_POLICY:
459 printf("NULL Policy: No statistics apply.\n");
460 break;
462 case ACM_CHINESE_WALL_POLICY:
463 printf("Chinese Wall Policy: No statistics apply.\n");
464 break;
466 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
467 dump_ste_stats((struct acm_ste_stats_buffer *) (stats_buffer +
468 ntohl(stats->
469 primary_stats_offset)));
470 break;
472 default:
473 printf("UNKNOWN PRIMARY POLICY ERROR!\n");
474 }
476 switch (ntohl(stats->secondary_policy_code)) {
477 case ACM_NULL_POLICY:
478 printf("NULL Policy: No statistics apply.\n");
479 break;
481 case ACM_CHINESE_WALL_POLICY:
482 printf("Chinese Wall Policy: No statistics apply.\n");
483 break;
485 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
486 dump_ste_stats((struct acm_ste_stats_buffer *) (stats_buffer +
487 ntohl(stats->
488 secondary_stats_offset)));
489 break;
491 default:
492 printf("UNKNOWN SECONDARY POLICY ERROR!\n");
493 }
494 xc_hypercall_buffer_free(xc_handle, stats_buffer);
495 return ret;
496 }
498 /***************************** main **************************************/
500 int main(int argc, char **argv)
501 {
503 xc_interface *xc_handle;
504 int ret = 0;
506 if (argc < 2)
507 usage(argv[0]);
510 if (!strcmp(argv[1], "getpolicy")) {
511 if (argc != 2)
512 usage(argv[0]);
514 if ((xc_handle = xc_interface_open()) == 0) {
515 printf("ERROR: Could not open xen privcmd device!\n");
516 exit(-1);
517 }
519 ret = acm_domain_getpolicy(xc_handle);
521 xc_interface_close(xc_handle);
522 } else if (!strcmp(argv[1], "loadpolicy")) {
523 if (argc != 3)
524 usage(argv[0]);
526 if ((xc_handle = xc_interface_open()) == 0) {
527 printf("ERROR: Could not open xen privcmd device!\n");
528 exit(-1);
529 }
531 ret = acm_domain_loadpolicy(xc_handle, argv[2]);
533 xc_interface_close(xc_handle);
534 } else if (!strcmp(argv[1], "dumpstats")) {
535 if (argc != 2)
536 usage(argv[0]);
538 if ((xc_handle = xc_interface_open()) == 0) {
539 printf("ERROR: Could not open xen privcmd device!\n");
540 exit(-1);
541 }
543 ret = acm_domain_dumpstats(xc_handle);
545 xc_interface_close(xc_handle);
546 } else if (!strcmp(argv[1], "dumppolicy")) {
547 uint32_t ssidref = 0xffffffff;
548 if (argc < 3 || argc > 4)
549 usage(argv[0]);
550 if (argc == 4) {
551 if (!sscanf(argv[3], "%i", &ssidref)) {
552 printf("Error: Could not parse ssidref.\n");
553 exit(-1);
554 }
555 }
556 ret = acm_domain_dumppolicy(argv[2], ssidref);
557 } else
558 usage(argv[0]);
560 return ret;
561 }