mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
Implement a simpler interface for the hypercalls to ACM. I put the parameters to all hypercalls into a union. On top of this I have implemented a shim layer for enabling ACM hypercalls on PPC. Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
461 lines
15 KiB
C
461 lines
15 KiB
C
/****************************************************************
|
|
* secpol_tool.c
|
|
*
|
|
* Copyright (C) 2005 IBM Corporation
|
|
*
|
|
* Authors:
|
|
* Reiner Sailer <sailer@watson.ibm.com>
|
|
* Stefan Berger <stefanb@watson.ibm.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 of the
|
|
* License.
|
|
*
|
|
* sHype policy management tool. This code runs in a domain and
|
|
* manages the Xen security policy by interacting with the
|
|
* Xen access control module via the privcmd device,
|
|
* which is translated into a acm_op hypercall into Xen.
|
|
*
|
|
* indent -i4 -kr -nut
|
|
*/
|
|
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <getopt.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <sys/ioctl.h>
|
|
#include <string.h>
|
|
#include <netinet/in.h>
|
|
#include <stdint.h>
|
|
#include <xen/acm.h>
|
|
#include <xen/acm_ops.h>
|
|
|
|
#include <xenctrl.h>
|
|
|
|
#define PERROR(_m, _a...) \
|
|
fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
|
|
errno, strerror(errno))
|
|
|
|
void usage(char *progname)
|
|
{
|
|
printf("Usage: %s ACTION\n"
|
|
"ACTION is one of:\n"
|
|
"\t getpolicy\n"
|
|
"\t dumpstats\n"
|
|
"\t loadpolicy <binary policy file>\n", progname);
|
|
exit(-1);
|
|
}
|
|
|
|
/*************************** DUMPS *******************************/
|
|
|
|
void acm_dump_chinesewall_buffer(void *buf, int buflen, uint16_t chwall_ref)
|
|
{
|
|
|
|
struct acm_chwall_policy_buffer *cwbuf =
|
|
(struct acm_chwall_policy_buffer *) buf;
|
|
domaintype_t *ssids, *conflicts, *running_types, *conflict_aggregate;
|
|
int i, j;
|
|
|
|
|
|
if (htonl(cwbuf->policy_code) != ACM_CHINESE_WALL_POLICY) {
|
|
printf("CHINESE WALL POLICY CODE not found ERROR!!\n");
|
|
return;
|
|
}
|
|
printf("\n\nChinese Wall policy:\n");
|
|
printf("====================\n");
|
|
printf("Policy version= %x.\n", ntohl(cwbuf->policy_version));
|
|
printf("Max Types = %x.\n", ntohl(cwbuf->chwall_max_types));
|
|
printf("Max Ssidrefs = %x.\n", ntohl(cwbuf->chwall_max_ssidrefs));
|
|
printf("Max ConfSets = %x.\n", ntohl(cwbuf->chwall_max_conflictsets));
|
|
printf("Ssidrefs Off = %x.\n", ntohl(cwbuf->chwall_ssid_offset));
|
|
printf("Conflicts Off = %x.\n",
|
|
ntohl(cwbuf->chwall_conflict_sets_offset));
|
|
printf("Runing T. Off = %x.\n",
|
|
ntohl(cwbuf->chwall_running_types_offset));
|
|
printf("C. Agg. Off = %x.\n",
|
|
ntohl(cwbuf->chwall_conflict_aggregate_offset));
|
|
printf("\nSSID To CHWALL-Type matrix:\n");
|
|
|
|
ssids = (domaintype_t *) (buf + ntohl(cwbuf->chwall_ssid_offset));
|
|
for (i = 0; i < ntohl(cwbuf->chwall_max_ssidrefs); i++) {
|
|
printf("\n ssidref%2x: ", i);
|
|
for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++)
|
|
printf("%02x ",
|
|
ntohs(ssids[i * ntohl(cwbuf->chwall_max_types) + j]));
|
|
if (i == chwall_ref)
|
|
printf(" <-- Domain-0");
|
|
}
|
|
printf("\n\nConfict Sets:\n");
|
|
conflicts =
|
|
(domaintype_t *) (buf + ntohl(cwbuf->chwall_conflict_sets_offset));
|
|
for (i = 0; i < ntohl(cwbuf->chwall_max_conflictsets); i++) {
|
|
printf("\n c-set%2x: ", i);
|
|
for (j = 0; j < ntohl(cwbuf->chwall_max_types); j++)
|
|
printf("%02x ",
|
|
ntohs(conflicts
|
|
[i * ntohl(cwbuf->chwall_max_types) + j]));
|
|
}
|
|
printf("\n");
|
|
|
|
printf("\nRunning\nTypes: ");
|
|
if (ntohl(cwbuf->chwall_running_types_offset)) {
|
|
running_types =
|
|
(domaintype_t *) (buf +
|
|
ntohl(cwbuf->chwall_running_types_offset));
|
|
for (i = 0; i < ntohl(cwbuf->chwall_max_types); i++) {
|
|
printf("%02x ", ntohs(running_types[i]));
|
|
}
|
|
printf("\n");
|
|
} else {
|
|
printf("Not Reported!\n");
|
|
}
|
|
printf("\nConflict\nAggregate Set: ");
|
|
if (ntohl(cwbuf->chwall_conflict_aggregate_offset)) {
|
|
conflict_aggregate =
|
|
(domaintype_t *) (buf +
|
|
ntohl(cwbuf->
|
|
chwall_conflict_aggregate_offset));
|
|
for (i = 0; i < ntohl(cwbuf->chwall_max_types); i++) {
|
|
printf("%02x ", ntohs(conflict_aggregate[i]));
|
|
}
|
|
printf("\n\n");
|
|
} else {
|
|
printf("Not Reported!\n");
|
|
}
|
|
}
|
|
|
|
void acm_dump_ste_buffer(void *buf, int buflen, uint16_t ste_ref)
|
|
{
|
|
|
|
struct acm_ste_policy_buffer *stebuf =
|
|
(struct acm_ste_policy_buffer *) buf;
|
|
domaintype_t *ssids;
|
|
int i, j;
|
|
|
|
|
|
if (ntohl(stebuf->policy_code) != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
|
|
printf("SIMPLE TYPE ENFORCEMENT POLICY CODE not found ERROR!!\n");
|
|
return;
|
|
}
|
|
printf("\nSimple Type Enforcement policy:\n");
|
|
printf("===============================\n");
|
|
printf("Policy version= %x.\n", ntohl(stebuf->policy_version));
|
|
printf("Max Types = %x.\n", ntohl(stebuf->ste_max_types));
|
|
printf("Max Ssidrefs = %x.\n", ntohl(stebuf->ste_max_ssidrefs));
|
|
printf("Ssidrefs Off = %x.\n", ntohl(stebuf->ste_ssid_offset));
|
|
printf("\nSSID To STE-Type matrix:\n");
|
|
|
|
ssids = (domaintype_t *) (buf + ntohl(stebuf->ste_ssid_offset));
|
|
for (i = 0; i < ntohl(stebuf->ste_max_ssidrefs); i++) {
|
|
printf("\n ssidref%2x: ", i);
|
|
for (j = 0; j < ntohl(stebuf->ste_max_types); j++)
|
|
printf("%02x ",
|
|
ntohs(ssids[i * ntohl(stebuf->ste_max_types) + j]));
|
|
if (i == ste_ref)
|
|
printf(" <-- Domain-0");
|
|
}
|
|
printf("\n\n");
|
|
}
|
|
|
|
void acm_dump_policy_buffer(void *buf, int buflen,
|
|
uint16_t chwall_ref, uint16_t ste_ref)
|
|
{
|
|
struct acm_policy_buffer *pol = (struct acm_policy_buffer *) buf;
|
|
char *policy_reference_name =
|
|
(buf + ntohl(pol->policy_reference_offset) +
|
|
sizeof(struct acm_policy_reference_buffer));
|
|
printf("\nPolicy dump:\n");
|
|
printf("============\n");
|
|
printf("POLICY REFERENCE = %s.\n", policy_reference_name);
|
|
printf("PolicyVer = %x.\n", ntohl(pol->policy_version));
|
|
printf("XML Vers. = %d.%d\n",
|
|
ntohl(pol->xml_pol_version.major),
|
|
ntohl(pol->xml_pol_version.minor));
|
|
printf("Magic = %x.\n", ntohl(pol->magic));
|
|
printf("Len = %x.\n", ntohl(pol->len));
|
|
printf("Primary = %s (c=%x, off=%x).\n",
|
|
ACM_POLICY_NAME(ntohl(pol->primary_policy_code)),
|
|
ntohl(pol->primary_policy_code),
|
|
ntohl(pol->primary_buffer_offset));
|
|
printf("Secondary = %s (c=%x, off=%x).\n",
|
|
ACM_POLICY_NAME(ntohl(pol->secondary_policy_code)),
|
|
ntohl(pol->secondary_policy_code),
|
|
ntohl(pol->secondary_buffer_offset));
|
|
switch (ntohl(pol->primary_policy_code)) {
|
|
case ACM_CHINESE_WALL_POLICY:
|
|
acm_dump_chinesewall_buffer(buf + ntohl(pol->primary_buffer_offset),
|
|
ntohl(pol->len) -
|
|
ntohl(pol->primary_buffer_offset),
|
|
chwall_ref);
|
|
break;
|
|
|
|
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
|
|
acm_dump_ste_buffer(buf + ntohl(pol->primary_buffer_offset),
|
|
ntohl(pol->len) -
|
|
ntohl(pol->primary_buffer_offset),
|
|
ste_ref);
|
|
break;
|
|
|
|
case ACM_NULL_POLICY:
|
|
printf("Primary policy is NULL Policy (n/a).\n");
|
|
break;
|
|
|
|
default:
|
|
printf("UNKNOWN POLICY!\n");
|
|
}
|
|
|
|
switch (ntohl(pol->secondary_policy_code)) {
|
|
case ACM_CHINESE_WALL_POLICY:
|
|
acm_dump_chinesewall_buffer(buf + ntohl(pol->secondary_buffer_offset),
|
|
ntohl(pol->len) -
|
|
ntohl(pol->secondary_buffer_offset),
|
|
chwall_ref);
|
|
break;
|
|
|
|
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
|
|
acm_dump_ste_buffer(buf + ntohl(pol->secondary_buffer_offset),
|
|
ntohl(pol->len) -
|
|
ntohl(pol->secondary_buffer_offset),
|
|
ste_ref);
|
|
break;
|
|
|
|
case ACM_NULL_POLICY:
|
|
printf("Secondary policy is NULL Policy (n/a).\n");
|
|
break;
|
|
|
|
default:
|
|
printf("UNKNOWN POLICY!\n");
|
|
}
|
|
}
|
|
|
|
/************************** get dom0 ssidref *****************************/
|
|
int acm_get_ssidref(int xc_handle, int domid, uint16_t *chwall_ref,
|
|
uint16_t *ste_ref)
|
|
{
|
|
int ret;
|
|
struct acm_getssid getssid;
|
|
char buf[4096];
|
|
struct acm_ssid_buffer *ssid = (struct acm_ssid_buffer *)buf;
|
|
set_xen_guest_handle(getssid.ssidbuf, buf);
|
|
getssid.ssidbuf_size = sizeof(buf);
|
|
getssid.get_ssid_by = ACM_GETBY_domainid;
|
|
getssid.id.domainid = domid;
|
|
ret = xc_acm_op(xc_handle, ACMOP_getssid, &getssid, sizeof(getssid));
|
|
if (ret == 0) {
|
|
*chwall_ref = ssid->ssidref & 0xffff;
|
|
*ste_ref = ssid->ssidref >> 16;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/******************************* get policy ******************************/
|
|
|
|
#define PULL_CACHE_SIZE 8192
|
|
uint8_t pull_buffer[PULL_CACHE_SIZE];
|
|
|
|
int acm_domain_getpolicy(int xc_handle)
|
|
{
|
|
struct acm_getpolicy getpolicy;
|
|
int ret;
|
|
uint16_t chwall_ref, ste_ref;
|
|
|
|
memset(pull_buffer, 0x00, sizeof(pull_buffer));
|
|
set_xen_guest_handle(getpolicy.pullcache, pull_buffer);
|
|
getpolicy.pullcache_size = sizeof(pull_buffer);
|
|
ret = xc_acm_op(xc_handle, ACMOP_getpolicy, &getpolicy, sizeof(getpolicy));
|
|
if (ret >= 0) {
|
|
ret = acm_get_ssidref(xc_handle, 0, &chwall_ref, &ste_ref);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
printf("ACM operation failed: errno=%d\n", errno);
|
|
if (errno == EACCES)
|
|
fprintf(stderr, "ACM operation failed -- need to"
|
|
" rebuild the user-space tool set?\n");
|
|
}
|
|
|
|
/* dump policy */
|
|
acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer),
|
|
chwall_ref, ste_ref);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/************************ load binary policy ******************************/
|
|
|
|
int acm_domain_loadpolicy(int xc_handle, const char *filename)
|
|
{
|
|
struct stat mystat;
|
|
int ret, fd;
|
|
off_t len;
|
|
uint8_t *buffer;
|
|
uint16_t chwall_ssidref, ste_ssidref;
|
|
|
|
if ((ret = stat(filename, &mystat))) {
|
|
printf("File %s not found.\n", filename);
|
|
goto out;
|
|
}
|
|
|
|
len = mystat.st_size;
|
|
if ((buffer = malloc(len)) == NULL) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
if ((fd = open(filename, O_RDONLY)) <= 0) {
|
|
ret = -ENOENT;
|
|
printf("File %s not found.\n", filename);
|
|
goto free_out;
|
|
}
|
|
ret =acm_get_ssidref(xc_handle, 0, &chwall_ssidref, &ste_ssidref);
|
|
if (ret < 0) {
|
|
goto free_out;
|
|
}
|
|
if (len == read(fd, buffer, len)) {
|
|
struct acm_setpolicy setpolicy;
|
|
/* dump it and then push it down into xen/acm */
|
|
acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref);
|
|
set_xen_guest_handle(setpolicy.pushcache, buffer);
|
|
setpolicy.pushcache_size = len;
|
|
ret = xc_acm_op(xc_handle, ACMOP_setpolicy, &setpolicy, sizeof(setpolicy));
|
|
|
|
if (ret)
|
|
printf
|
|
("ERROR setting policy.\n");
|
|
else
|
|
printf("Successfully changed policy.\n");
|
|
|
|
} else {
|
|
ret = -1;
|
|
}
|
|
close(fd);
|
|
free_out:
|
|
free(buffer);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/************************ dump hook statistics ******************************/
|
|
void dump_ste_stats(struct acm_ste_stats_buffer *ste_stats)
|
|
{
|
|
printf("STE-Policy Security Hook Statistics:\n");
|
|
printf("ste: event_channel eval_count = %d\n",
|
|
ntohl(ste_stats->ec_eval_count));
|
|
printf("ste: event_channel denied_count = %d\n",
|
|
ntohl(ste_stats->ec_denied_count));
|
|
printf("ste: event_channel cache_hit_count = %d\n",
|
|
ntohl(ste_stats->ec_cachehit_count));
|
|
printf("ste:\n");
|
|
printf("ste: grant_table eval_count = %d\n",
|
|
ntohl(ste_stats->gt_eval_count));
|
|
printf("ste: grant_table denied_count = %d\n",
|
|
ntohl(ste_stats->gt_denied_count));
|
|
printf("ste: grant_table cache_hit_count = %d\n",
|
|
ntohl(ste_stats->gt_cachehit_count));
|
|
}
|
|
|
|
#define PULL_STATS_SIZE 8192
|
|
int acm_domain_dumpstats(int xc_handle)
|
|
{
|
|
uint8_t stats_buffer[PULL_STATS_SIZE];
|
|
struct acm_dumpstats dumpstats;
|
|
int ret;
|
|
struct acm_stats_buffer *stats;
|
|
|
|
memset(stats_buffer, 0x00, sizeof(stats_buffer));
|
|
set_xen_guest_handle(dumpstats.pullcache, stats_buffer);
|
|
dumpstats.pullcache_size = sizeof(stats_buffer);
|
|
ret = xc_acm_op(xc_handle, ACMOP_dumpstats, &dumpstats, sizeof(dumpstats));
|
|
|
|
if (ret < 0) {
|
|
printf
|
|
("ERROR dumping policy stats. Try 'xm dmesg' to see details.\n");
|
|
return ret;
|
|
}
|
|
stats = (struct acm_stats_buffer *) stats_buffer;
|
|
|
|
printf("\nPolicy dump:\n");
|
|
printf("============\n");
|
|
printf("Magic = %x.\n", ntohl(stats->magic));
|
|
printf("Len = %x.\n", ntohl(stats->len));
|
|
|
|
switch (ntohl(stats->primary_policy_code)) {
|
|
case ACM_NULL_POLICY:
|
|
printf("NULL Policy: No statistics apply.\n");
|
|
break;
|
|
|
|
case ACM_CHINESE_WALL_POLICY:
|
|
printf("Chinese Wall Policy: No statistics apply.\n");
|
|
break;
|
|
|
|
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
|
|
dump_ste_stats((struct acm_ste_stats_buffer *) (stats_buffer +
|
|
ntohl(stats->
|
|
primary_stats_offset)));
|
|
break;
|
|
|
|
default:
|
|
printf("UNKNOWN PRIMARY POLICY ERROR!\n");
|
|
}
|
|
|
|
switch (ntohl(stats->secondary_policy_code)) {
|
|
case ACM_NULL_POLICY:
|
|
printf("NULL Policy: No statistics apply.\n");
|
|
break;
|
|
|
|
case ACM_CHINESE_WALL_POLICY:
|
|
printf("Chinese Wall Policy: No statistics apply.\n");
|
|
break;
|
|
|
|
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
|
|
dump_ste_stats((struct acm_ste_stats_buffer *) (stats_buffer +
|
|
ntohl(stats->
|
|
secondary_stats_offset)));
|
|
break;
|
|
|
|
default:
|
|
printf("UNKNOWN SECONDARY POLICY ERROR!\n");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/***************************** main **************************************/
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
|
|
int xc_handle, ret = 0;
|
|
|
|
if (argc < 2)
|
|
usage(argv[0]);
|
|
|
|
if ((xc_handle = xc_interface_open()) <= 0) {
|
|
printf("ERROR: Could not open xen privcmd device!\n");
|
|
exit(-1);
|
|
}
|
|
|
|
if (!strcmp(argv[1], "getpolicy")) {
|
|
if (argc != 2)
|
|
usage(argv[0]);
|
|
ret = acm_domain_getpolicy(xc_handle);
|
|
} else if (!strcmp(argv[1], "loadpolicy")) {
|
|
if (argc != 3)
|
|
usage(argv[0]);
|
|
ret = acm_domain_loadpolicy(xc_handle, argv[2]);
|
|
} else if (!strcmp(argv[1], "dumpstats")) {
|
|
if (argc != 2)
|
|
usage(argv[0]);
|
|
ret = acm_domain_dumpstats(xc_handle);
|
|
} else
|
|
usage(argv[0]);
|
|
|
|
xc_interface_close(xc_handle);
|
|
return ret;
|
|
}
|