ia64/xen-unstable

view tools/security/secpol_tool.c @ 9832:ad30019015a2

This patch adds support in the hypervisor for the policy name attribute
introduced into security policies. It also fixes a minor problem related
to handling unsupported boot policies.

Signed-off by: Reiner Sailer <sailer@us.ibm.com>
author smh22@firebug.cl.cam.ac.uk
date Mon Apr 24 10:51:50 2006 +0100 (2006-04-24)
parents 8aac8746047b
children 24dbb153ab39
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 a /proc/xen/privcmd proc-ioctl,
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/acm.h>
38 #include <xen/acm_ops.h>
39 #include <xen/linux/privcmd.h>
41 #define PERROR(_m, _a...) \
42 fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
43 errno, strerror(errno))
45 void usage(char *progname)
46 {
47 printf("Usage: %s ACTION\n"
48 "ACTION is one of:\n"
49 "\t getpolicy\n"
50 "\t dumpstats\n"
51 "\t loadpolicy <binary policy file>\n", progname);
52 exit(-1);
53 }
55 static inline int do_policycmd(int xc_handle, unsigned int cmd,
56 unsigned long data)
57 {
58 return ioctl(xc_handle, cmd, data);
59 }
61 static inline int do_xen_hypercall(int xc_handle,
62 privcmd_hypercall_t * hypercall)
63 {
64 return do_policycmd(xc_handle,
65 IOCTL_PRIVCMD_HYPERCALL,
66 (unsigned long) hypercall);
67 }
69 static inline int do_acm_op(int xc_handle, struct acm_op *op)
70 {
71 int ret = -1;
72 privcmd_hypercall_t hypercall;
74 op->interface_version = ACM_INTERFACE_VERSION;
76 hypercall.op = __HYPERVISOR_acm_op;
77 hypercall.arg[0] = (unsigned long) op;
79 if (mlock(op, sizeof(*op)) != 0) {
80 PERROR("Could not lock memory for Xen policy hypercall");
81 goto out1;
82 }
84 if ((ret = do_xen_hypercall(xc_handle, &hypercall)) < 0) {
85 printf("ACM operation failed: errno=%d\n", errno);
86 if (errno == EACCES)
87 fprintf(stderr, "ACM operation failed -- need to"
88 " rebuild the user-space tool set?\n");
89 goto out2;
90 }
92 out2:(void) munlock(op, sizeof(*op));
93 out1:return ret;
94 }
96 /*************************** DUMPS *******************************/
98 void acm_dump_chinesewall_buffer(void *buf, int buflen)
99 {
101 struct acm_chwall_policy_buffer *cwbuf =
102 (struct acm_chwall_policy_buffer *) buf;
103 domaintype_t *ssids, *conflicts, *running_types, *conflict_aggregate;
104 int i, j;
107 if (htonl(cwbuf->policy_code) != ACM_CHINESE_WALL_POLICY) {
108 printf("CHINESE WALL POLICY CODE not found ERROR!!\n");
109 return;
110 }
111 printf("\n\nChinese Wall policy:\n");
112 printf("====================\n");
113 printf("Policy version= %x.\n", ntohl(cwbuf->policy_version));
114 printf("Max Types = %x.\n", ntohl(cwbuf->chwall_max_types));
115 printf("Max Ssidrefs = %x.\n", ntohl(cwbuf->chwall_max_ssidrefs));
116 printf("Max ConfSets = %x.\n", ntohl(cwbuf->chwall_max_conflictsets));
117 printf("Ssidrefs Off = %x.\n", ntohl(cwbuf->chwall_ssid_offset));
118 printf("Conflicts Off = %x.\n",
119 ntohl(cwbuf->chwall_conflict_sets_offset));
120 printf("Runing T. Off = %x.\n",
121 ntohl(cwbuf->chwall_running_types_offset));
122 printf("C. Agg. Off = %x.\n",
123 ntohl(cwbuf->chwall_conflict_aggregate_offset));
124 printf("\nSSID To CHWALL-Type matrix:\n");
126 ssids = (domaintype_t *) (buf + ntohl(cwbuf->chwall_ssid_offset));
127 for (i = 0; i < ntohl(cwbuf->chwall_max_ssidrefs); i++) {
128 printf("\n ssidref%2x: ", i);
129 for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++)
130 printf("%02x ",
131 ntohs(ssids[i * ntohl(cwbuf->chwall_max_types) + j]));
132 }
133 printf("\n\nConfict Sets:\n");
134 conflicts =
135 (domaintype_t *) (buf + ntohl(cwbuf->chwall_conflict_sets_offset));
136 for (i = 0; i < ntohl(cwbuf->chwall_max_conflictsets); i++) {
137 printf("\n c-set%2x: ", i);
138 for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++)
139 printf("%02x ",
140 ntohs(conflicts
141 [i * ntohl(cwbuf->chwall_max_types) + j]));
142 }
143 printf("\n");
145 printf("\nRunning\nTypes: ");
146 if (ntohl(cwbuf->chwall_running_types_offset)) {
147 running_types =
148 (domaintype_t *) (buf +
149 ntohl(cwbuf->chwall_running_types_offset));
150 for (i = 0; i < ntohl(cwbuf->chwall_max_types); i++) {
151 printf("%02x ", ntohs(running_types[i]));
152 }
153 printf("\n");
154 } else {
155 printf("Not Reported!\n");
156 }
157 printf("\nConflict\nAggregate Set: ");
158 if (ntohl(cwbuf->chwall_conflict_aggregate_offset)) {
159 conflict_aggregate =
160 (domaintype_t *) (buf +
161 ntohl(cwbuf->
162 chwall_conflict_aggregate_offset));
163 for (i = 0; i < ntohl(cwbuf->chwall_max_types); i++) {
164 printf("%02x ", ntohs(conflict_aggregate[i]));
165 }
166 printf("\n\n");
167 } else {
168 printf("Not Reported!\n");
169 }
170 }
172 void acm_dump_ste_buffer(void *buf, int buflen)
173 {
175 struct acm_ste_policy_buffer *stebuf =
176 (struct acm_ste_policy_buffer *) buf;
177 domaintype_t *ssids;
178 int i, j;
181 if (ntohl(stebuf->policy_code) != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
182 printf("SIMPLE TYPE ENFORCEMENT POLICY CODE not found ERROR!!\n");
183 return;
184 }
185 printf("\nSimple Type Enforcement policy:\n");
186 printf("===============================\n");
187 printf("Policy version= %x.\n", ntohl(stebuf->policy_version));
188 printf("Max Types = %x.\n", ntohl(stebuf->ste_max_types));
189 printf("Max Ssidrefs = %x.\n", ntohl(stebuf->ste_max_ssidrefs));
190 printf("Ssidrefs Off = %x.\n", ntohl(stebuf->ste_ssid_offset));
191 printf("\nSSID To STE-Type matrix:\n");
193 ssids = (domaintype_t *) (buf + ntohl(stebuf->ste_ssid_offset));
194 for (i = 0; i < ntohl(stebuf->ste_max_ssidrefs); i++) {
195 printf("\n ssidref%2x: ", i);
196 for (j = 0; j < ntohl(stebuf->ste_max_types); j++)
197 printf("%02x ",
198 ntohs(ssids[i * ntohl(stebuf->ste_max_types) + j]));
199 }
200 printf("\n\n");
201 }
203 void acm_dump_policy_buffer(void *buf, int buflen)
204 {
205 struct acm_policy_buffer *pol = (struct acm_policy_buffer *) buf;
206 char *policy_reference_name =
207 (buf + ntohl(pol->policy_reference_offset) +
208 sizeof(struct acm_policy_reference_buffer));
209 printf("\nPolicy dump:\n");
210 printf("============\n");
211 printf("POLICY REFERENCE = %s.\n", policy_reference_name);
212 printf("PolicyVer = %x.\n", ntohl(pol->policy_version));
213 printf("Magic = %x.\n", ntohl(pol->magic));
214 printf("Len = %x.\n", ntohl(pol->len));
215 printf("Primary = %s (c=%x, off=%x).\n",
216 ACM_POLICY_NAME(ntohl(pol->primary_policy_code)),
217 ntohl(pol->primary_policy_code),
218 ntohl(pol->primary_buffer_offset));
219 printf("Secondary = %s (c=%x, off=%x).\n",
220 ACM_POLICY_NAME(ntohl(pol->secondary_policy_code)),
221 ntohl(pol->secondary_policy_code),
222 ntohl(pol->secondary_buffer_offset));
223 switch (ntohl(pol->primary_policy_code)) {
224 case ACM_CHINESE_WALL_POLICY:
225 acm_dump_chinesewall_buffer(buf +
226 ntohl(pol->primary_buffer_offset),
227 ntohl(pol->len) -
228 ntohl(pol->primary_buffer_offset));
229 break;
231 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
232 acm_dump_ste_buffer(buf + ntohl(pol->primary_buffer_offset),
233 ntohl(pol->len) -
234 ntohl(pol->primary_buffer_offset));
235 break;
237 case ACM_NULL_POLICY:
238 printf("Primary policy is NULL Policy (n/a).\n");
239 break;
241 default:
242 printf("UNKNOWN POLICY!\n");
243 }
245 switch (ntohl(pol->secondary_policy_code)) {
246 case ACM_CHINESE_WALL_POLICY:
247 acm_dump_chinesewall_buffer(buf +
248 ntohl(pol->secondary_buffer_offset),
249 ntohl(pol->len) -
250 ntohl(pol->secondary_buffer_offset));
251 break;
253 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
254 acm_dump_ste_buffer(buf + ntohl(pol->secondary_buffer_offset),
255 ntohl(pol->len) -
256 ntohl(pol->secondary_buffer_offset));
257 break;
259 case ACM_NULL_POLICY:
260 printf("Secondary policy is NULL Policy (n/a).\n");
261 break;
263 default:
264 printf("UNKNOWN POLICY!\n");
265 }
266 }
268 /******************************* get policy ******************************/
270 #define PULL_CACHE_SIZE 8192
271 uint8_t pull_buffer[PULL_CACHE_SIZE];
272 int acm_domain_getpolicy(int xc_handle)
273 {
274 struct acm_op op;
275 int ret;
277 memset(pull_buffer, 0x00, sizeof(pull_buffer));
278 op.cmd = ACM_GETPOLICY;
279 op.interface_version = ACM_INTERFACE_VERSION;
280 op.u.getpolicy.pullcache = (void *) pull_buffer;
281 op.u.getpolicy.pullcache_size = sizeof(pull_buffer);
282 ret = do_acm_op(xc_handle, &op);
283 /* dump policy */
284 acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer));
285 return ret;
286 }
288 /************************ load binary policy ******************************/
290 int acm_domain_loadpolicy(int xc_handle, const char *filename)
291 {
292 struct stat mystat;
293 int ret, fd;
294 off_t len;
295 uint8_t *buffer;
297 if ((ret = stat(filename, &mystat))) {
298 printf("File %s not found.\n", filename);
299 goto out;
300 }
302 len = mystat.st_size;
303 if ((buffer = malloc(len)) == NULL) {
304 ret = -ENOMEM;
305 goto out;
306 }
307 if ((fd = open(filename, O_RDONLY)) <= 0) {
308 ret = -ENOENT;
309 printf("File %s not found.\n", filename);
310 goto free_out;
311 }
312 if (len == read(fd, buffer, len)) {
313 struct acm_op op;
314 /* dump it and then push it down into xen/acm */
315 acm_dump_policy_buffer(buffer, len);
316 op.cmd = ACM_SETPOLICY;
317 op.interface_version = ACM_INTERFACE_VERSION;
318 op.u.setpolicy.pushcache = (void *) buffer;
319 op.u.setpolicy.pushcache_size = len;
320 ret = do_acm_op(xc_handle, &op);
322 if (ret)
323 printf
324 ("ERROR setting policy.\n");
325 else
326 printf("Successfully changed policy.\n");
328 } else {
329 ret = -1;
330 }
331 close(fd);
332 free_out:
333 free(buffer);
334 out:
335 return ret;
336 }
338 /************************ dump hook statistics ******************************/
339 void dump_ste_stats(struct acm_ste_stats_buffer *ste_stats)
340 {
341 printf("STE-Policy Security Hook Statistics:\n");
342 printf("ste: event_channel eval_count = %d\n",
343 ntohl(ste_stats->ec_eval_count));
344 printf("ste: event_channel denied_count = %d\n",
345 ntohl(ste_stats->ec_denied_count));
346 printf("ste: event_channel cache_hit_count = %d\n",
347 ntohl(ste_stats->ec_cachehit_count));
348 printf("ste:\n");
349 printf("ste: grant_table eval_count = %d\n",
350 ntohl(ste_stats->gt_eval_count));
351 printf("ste: grant_table denied_count = %d\n",
352 ntohl(ste_stats->gt_denied_count));
353 printf("ste: grant_table cache_hit_count = %d\n",
354 ntohl(ste_stats->gt_cachehit_count));
355 }
357 #define PULL_STATS_SIZE 8192
358 int acm_domain_dumpstats(int xc_handle)
359 {
360 uint8_t stats_buffer[PULL_STATS_SIZE];
361 struct acm_op op;
362 int ret;
363 struct acm_stats_buffer *stats;
365 memset(stats_buffer, 0x00, sizeof(stats_buffer));
366 op.cmd = ACM_DUMPSTATS;
367 op.interface_version = ACM_INTERFACE_VERSION;
368 op.u.dumpstats.pullcache = (void *) stats_buffer;
369 op.u.dumpstats.pullcache_size = sizeof(stats_buffer);
370 ret = do_acm_op(xc_handle, &op);
372 if (ret < 0) {
373 printf
374 ("ERROR dumping policy stats. Try 'xm dmesg' to see details.\n");
375 return ret;
376 }
377 stats = (struct acm_stats_buffer *) stats_buffer;
379 printf("\nPolicy dump:\n");
380 printf("============\n");
381 printf("Magic = %x.\n", ntohl(stats->magic));
382 printf("Len = %x.\n", ntohl(stats->len));
384 switch (ntohl(stats->primary_policy_code)) {
385 case ACM_NULL_POLICY:
386 printf("NULL Policy: No statistics apply.\n");
387 break;
389 case ACM_CHINESE_WALL_POLICY:
390 printf("Chinese Wall Policy: No statistics apply.\n");
391 break;
393 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
394 dump_ste_stats((struct acm_ste_stats_buffer *) (stats_buffer +
395 ntohl(stats->
396 primary_stats_offset)));
397 break;
399 default:
400 printf("UNKNOWN PRIMARY POLICY ERROR!\n");
401 }
403 switch (ntohl(stats->secondary_policy_code)) {
404 case ACM_NULL_POLICY:
405 printf("NULL Policy: No statistics apply.\n");
406 break;
408 case ACM_CHINESE_WALL_POLICY:
409 printf("Chinese Wall Policy: No statistics apply.\n");
410 break;
412 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
413 dump_ste_stats((struct acm_ste_stats_buffer *) (stats_buffer +
414 ntohl(stats->
415 secondary_stats_offset)));
416 break;
418 default:
419 printf("UNKNOWN SECONDARY POLICY ERROR!\n");
420 }
421 return ret;
422 }
424 /***************************** main **************************************/
426 int main(int argc, char **argv)
427 {
429 int acm_cmd_fd, ret = 0;
431 if (argc < 2)
432 usage(argv[0]);
434 if ((acm_cmd_fd = open("/proc/xen/privcmd", O_RDONLY)) <= 0) {
435 printf("ERROR: Could not open xen privcmd device!\n");
436 exit(-1);
437 }
439 if (!strcmp(argv[1], "getpolicy")) {
440 if (argc != 2)
441 usage(argv[0]);
442 ret = acm_domain_getpolicy(acm_cmd_fd);
443 } else if (!strcmp(argv[1], "loadpolicy")) {
444 if (argc != 3)
445 usage(argv[0]);
446 ret = acm_domain_loadpolicy(acm_cmd_fd, argv[2]);
447 } else if (!strcmp(argv[1], "dumpstats")) {
448 if (argc != 2)
449 usage(argv[0]);
450 ret = acm_domain_dumpstats(acm_cmd_fd);
451 } else
452 usage(argv[0]);
454 close(acm_cmd_fd);
455 return ret;
456 }