mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
This patch to the Xen access control module (ACM) and tools:
1. adapts ACM hooks to the slightly changed event channel structure 2. introduces an ACM_GETDECISION command, which enables authorized domains to retrieve policy decisions regarding the sharing of resources (STE policy) from the Xen hypervisor 3. includes cleanup (warnings I found when applying analysis tools such as beam or flawfinder to the ACM code) The get_decision function is useful to enforce: * the security policy on network traffic in the network backends in domain 0; currently there is no enforcement in Dom0 and all packets flow freely * the security policy in block device backends to control which domains can access which vdisk resources I have added a small test program that shows how to use the get_decision ACM interface call, it is in tools/security/get_decision.c and will be compiled together with the policy tools. As usual, the ACM is unconfigured until you switch on a security policy on in Config.mk. Signed-off: Reiner Sailer <sailer@us.ibm.com>
This commit is contained in:
1 parent
d52306f795
commit
cc677c9d4e
16 files changed
+1741
-1248
No files matched your search
@@ -43,6 +43,7 @@ endif
|
||||
build: mk-symlinks
|
||||
$(MAKE) secpol_tool
|
||||
$(MAKE) secpol_xml2bin
|
||||
$(MAKE) get_decision
|
||||
chmod 700 ./setlabel.sh
|
||||
chmod 700 ./updategrub.sh
|
||||
chmod 700 ./getlabel.sh
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/****************************************************************
|
||||
* get_decision.c
|
||||
*
|
||||
* Copyright (C) 2005 IBM Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Reiner Sailer <sailer@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.
|
||||
*
|
||||
* An example program that shows how to retrieve an access control
|
||||
* decision from the hypervisor ACM based on the currently active policy.
|
||||
*
|
||||
*/
|
||||
|
||||
#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 <xen/acm.h>
|
||||
#include <xen/acm_ops.h>
|
||||
#include <xen/linux/privcmd.h>
|
||||
|
||||
#define PERROR(_m, _a...) \
|
||||
fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
|
||||
errno, strerror(errno))
|
||||
|
||||
void usage(char *progname)
|
||||
{
|
||||
printf("Use: %s \n", progname);
|
||||
printf(" Test program illustrating the retrieval of\n");
|
||||
printf(" access control decisions from xen. At this time,\n");
|
||||
printf(" only sharing (STE) policy decisions are supported.\n");
|
||||
printf(" parameter options:\n");
|
||||
printf("\t -i domid -i domid\n");
|
||||
printf("\t -i domid -s ssidref\n");
|
||||
printf("\t -s ssidref -s ssidref\n\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static inline int do_policycmd(int xc_handle, unsigned int cmd,
|
||||
unsigned long data)
|
||||
{
|
||||
return ioctl(xc_handle, cmd, data);
|
||||
}
|
||||
|
||||
static inline int do_xen_hypercall(int xc_handle,
|
||||
privcmd_hypercall_t * hypercall)
|
||||
{
|
||||
return do_policycmd(xc_handle,
|
||||
IOCTL_PRIVCMD_HYPERCALL,
|
||||
(unsigned long) hypercall);
|
||||
}
|
||||
|
||||
static inline int do_acm_op(int xc_handle, struct acm_op *op)
|
||||
{
|
||||
int ret = -1;
|
||||
privcmd_hypercall_t hypercall;
|
||||
|
||||
op->interface_version = ACM_INTERFACE_VERSION;
|
||||
|
||||
hypercall.op = __HYPERVISOR_acm_op;
|
||||
hypercall.arg[0] = (unsigned long) op;
|
||||
|
||||
if (mlock(op, sizeof(*op)) != 0) {
|
||||
PERROR("Could not lock memory for Xen policy hypercall");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if ((ret = do_xen_hypercall(xc_handle, &hypercall)) < 0) {
|
||||
if (errno == EACCES)
|
||||
fprintf(stderr, "ACM operation failed -- need to"
|
||||
" rebuild the user-space tool set?\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
out2:(void) munlock(op, sizeof(*op));
|
||||
out1:return ret;
|
||||
}
|
||||
|
||||
|
||||
/************************ get decision ******************************/
|
||||
|
||||
/* this example uses two domain ids and retrieves the decision if these domains
|
||||
* can share information (useful, i.e., to enforce policy onto network traffic in dom0
|
||||
*/
|
||||
int acm_get_decision(int xc_handle, int argc, char *const argv[])
|
||||
{
|
||||
struct acm_op op;
|
||||
int ret;
|
||||
|
||||
op.cmd = ACM_GETDECISION;
|
||||
op.interface_version = ACM_INTERFACE_VERSION;
|
||||
op.u.getdecision.get_decision_by1 = UNSET;
|
||||
op.u.getdecision.get_decision_by2 = UNSET;
|
||||
op.u.getdecision.hook = SHARING;
|
||||
|
||||
while (1) {
|
||||
int c = getopt(argc, argv, "i:s:");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
if (c == 'i') {
|
||||
if (op.u.getdecision.get_decision_by1 == UNSET) {
|
||||
op.u.getdecision.get_decision_by1 = DOMAINID;
|
||||
op.u.getdecision.id1.domainid = strtoul(optarg, NULL, 0);
|
||||
} else if (op.u.getdecision.get_decision_by2 == UNSET) {
|
||||
op.u.getdecision.get_decision_by2 = DOMAINID;
|
||||
op.u.getdecision.id2.domainid = strtoul(optarg, NULL, 0);
|
||||
} else
|
||||
usage(argv[0]);
|
||||
} else if (c == 's') {
|
||||
if (op.u.getdecision.get_decision_by1 == UNSET) {
|
||||
op.u.getdecision.get_decision_by1 = SSIDREF;
|
||||
op.u.getdecision.id1.ssidref = strtoul(optarg, NULL, 0);
|
||||
} else if (op.u.getdecision.get_decision_by2 == UNSET) {
|
||||
op.u.getdecision.get_decision_by2 = SSIDREF;
|
||||
op.u.getdecision.id2.ssidref = strtoul(optarg, NULL, 0);
|
||||
} else
|
||||
usage(argv[0]);
|
||||
} else
|
||||
usage(argv[0]);
|
||||
}
|
||||
if ((op.u.getdecision.get_decision_by1 == UNSET) ||
|
||||
(op.u.getdecision.get_decision_by2 == UNSET))
|
||||
usage(argv[0]);
|
||||
|
||||
if ((ret = do_acm_op(xc_handle, &op))) {
|
||||
printf("%s: Error getting decision (%d).\n", __func__, ret);
|
||||
printf("%s: decision = %s.\n", __func__,
|
||||
(op.u.getdecision.acm_decision ==
|
||||
ACM_ACCESS_PERMITTED) ? "PERMITTED" : ((op.u.getdecision.
|
||||
acm_decision ==
|
||||
ACM_ACCESS_DENIED)
|
||||
? "DENIED" :
|
||||
"ERROR"));
|
||||
return ret;
|
||||
}
|
||||
return op.u.getdecision.acm_decision;
|
||||
}
|
||||
|
||||
/***************************** main **************************************/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
int acm_cmd_fd, ret = 0;
|
||||
|
||||
if (argc < 5)
|
||||
usage(argv[0]);
|
||||
|
||||
if ((acm_cmd_fd = open("/proc/xen/privcmd", O_RDONLY)) <= 0) {
|
||||
printf("ERROR: Could not open xen privcmd device!\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ret = acm_get_decision(acm_cmd_fd, argc, argv);
|
||||
|
||||
printf("Decision: %s (%d)\n",
|
||||
(ret == ACM_ACCESS_PERMITTED) ? "PERMITTED" :
|
||||
((ret == ACM_ACCESS_DENIED) ? "DENIED" : "ERROR"), ret);
|
||||
|
||||
close(acm_cmd_fd);
|
||||
return ret;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ static inline int do_xen_hypercall(int xc_handle,
|
||||
(unsigned long) hypercall);
|
||||
}
|
||||
|
||||
static inline int do_acm_op(int xc_handle, acm_op_t * op)
|
||||
static inline int do_acm_op(int xc_handle, struct acm_op * op)
|
||||
{
|
||||
int ret = -1;
|
||||
privcmd_hypercall_t hypercall;
|
||||
@@ -275,10 +275,10 @@ void acm_dump_policy_buffer(void *buf, int buflen)
|
||||
/******************************* get policy ******************************/
|
||||
|
||||
#define PULL_CACHE_SIZE 8192
|
||||
u8 pull_buffer[PULL_CACHE_SIZE];
|
||||
uint8_t pull_buffer[PULL_CACHE_SIZE];
|
||||
int acm_domain_getpolicy(int xc_handle)
|
||||
{
|
||||
acm_op_t op;
|
||||
struct acm_op op;
|
||||
int ret;
|
||||
|
||||
memset(pull_buffer, 0x00, sizeof(pull_buffer));
|
||||
@@ -299,7 +299,7 @@ int acm_domain_loadpolicy(int xc_handle, const char *filename)
|
||||
struct stat mystat;
|
||||
int ret, fd;
|
||||
off_t len;
|
||||
u8 *buffer;
|
||||
uint8_t *buffer;
|
||||
|
||||
if ((ret = stat(filename, &mystat)))
|
||||
{
|
||||
@@ -321,7 +321,7 @@ int acm_domain_loadpolicy(int xc_handle, const char *filename)
|
||||
}
|
||||
if (len == read(fd, buffer, len))
|
||||
{
|
||||
acm_op_t op;
|
||||
struct acm_op op;
|
||||
/* dump it and then push it down into xen/acm */
|
||||
acm_dump_policy_buffer(buffer, len);
|
||||
op.cmd = ACM_SETPOLICY;
|
||||
@@ -368,8 +368,8 @@ void dump_ste_stats(struct acm_ste_stats_buffer *ste_stats)
|
||||
#define PULL_STATS_SIZE 8192
|
||||
int acm_domain_dumpstats(int xc_handle)
|
||||
{
|
||||
u8 stats_buffer[PULL_STATS_SIZE];
|
||||
acm_op_t op;
|
||||
uint8_t stats_buffer[PULL_STATS_SIZE];
|
||||
struct acm_op op;
|
||||
int ret;
|
||||
struct acm_stats_buffer *stats;
|
||||
|
||||
@@ -442,7 +442,7 @@ int acm_domain_getssid(int xc_handle, int argc, char * const argv[])
|
||||
/* this includes header and a set of types */
|
||||
#define MAX_SSIDBUFFER 2000
|
||||
int ret, i;
|
||||
acm_op_t op;
|
||||
struct acm_op op;
|
||||
struct acm_ssid_buffer *hdr;
|
||||
unsigned char *buf;
|
||||
int nice_print = 1;
|
||||
|
||||
+511
-402
@@ -26,7 +26,10 @@
|
||||
* in which case all types of a new domain must be conflict-free
|
||||
* with all types of already running domains.
|
||||
*
|
||||
* indent -i4 -kr -nut
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/errno.h>
|
||||
#include <xen/types.h>
|
||||
@@ -48,270 +51,333 @@ struct chwall_binary_policy chwall_bin_pol;
|
||||
*/
|
||||
int acm_init_chwall_policy(void)
|
||||
{
|
||||
/* minimal startup policy; policy write-locked already */
|
||||
chwall_bin_pol.max_types = 1;
|
||||
chwall_bin_pol.max_ssidrefs = 2;
|
||||
chwall_bin_pol.max_conflictsets = 1;
|
||||
chwall_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types);
|
||||
chwall_bin_pol.conflict_sets = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types);
|
||||
chwall_bin_pol.running_types = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
|
||||
chwall_bin_pol.conflict_aggregate_set = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
|
||||
|
||||
if ((chwall_bin_pol.conflict_sets == NULL) || (chwall_bin_pol.running_types == NULL) ||
|
||||
(chwall_bin_pol.ssidrefs == NULL) || (chwall_bin_pol.conflict_aggregate_set == NULL))
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
/* minimal startup policy; policy write-locked already */
|
||||
chwall_bin_pol.max_types = 1;
|
||||
chwall_bin_pol.max_ssidrefs = 2;
|
||||
chwall_bin_pol.max_conflictsets = 1;
|
||||
chwall_bin_pol.ssidrefs =
|
||||
(domaintype_t *) xmalloc_array(domaintype_t,
|
||||
chwall_bin_pol.max_ssidrefs *
|
||||
chwall_bin_pol.max_types);
|
||||
chwall_bin_pol.conflict_sets =
|
||||
(domaintype_t *) xmalloc_array(domaintype_t,
|
||||
chwall_bin_pol.max_conflictsets *
|
||||
chwall_bin_pol.max_types);
|
||||
chwall_bin_pol.running_types =
|
||||
(domaintype_t *) xmalloc_array(domaintype_t,
|
||||
chwall_bin_pol.max_types);
|
||||
chwall_bin_pol.conflict_aggregate_set =
|
||||
(domaintype_t *) xmalloc_array(domaintype_t,
|
||||
chwall_bin_pol.max_types);
|
||||
|
||||
/* initialize state */
|
||||
memset((void *)chwall_bin_pol.ssidrefs, 0, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types*sizeof(domaintype_t));
|
||||
memset((void *)chwall_bin_pol.conflict_sets, 0, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types*sizeof(domaintype_t));
|
||||
memset((void *)chwall_bin_pol.running_types, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));
|
||||
memset((void *)chwall_bin_pol.conflict_aggregate_set, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));
|
||||
return ACM_OK;
|
||||
if ((chwall_bin_pol.conflict_sets == NULL)
|
||||
|| (chwall_bin_pol.running_types == NULL)
|
||||
|| (chwall_bin_pol.ssidrefs == NULL)
|
||||
|| (chwall_bin_pol.conflict_aggregate_set == NULL))
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
|
||||
/* initialize state */
|
||||
memset((void *) chwall_bin_pol.ssidrefs, 0,
|
||||
chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types *
|
||||
sizeof(domaintype_t));
|
||||
memset((void *) chwall_bin_pol.conflict_sets, 0,
|
||||
chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types *
|
||||
sizeof(domaintype_t));
|
||||
memset((void *) chwall_bin_pol.running_types, 0,
|
||||
chwall_bin_pol.max_types * sizeof(domaintype_t));
|
||||
memset((void *) chwall_bin_pol.conflict_aggregate_set, 0,
|
||||
chwall_bin_pol.max_types * sizeof(domaintype_t));
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
|
||||
static int chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
|
||||
{
|
||||
struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid);
|
||||
traceprintk("%s.\n", __func__);
|
||||
if (chwall_ssidp == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
/*
|
||||
* depending on wheter chwall is primary or secondary, get the respective
|
||||
* part of the global ssidref (same way we'll get the partial ssid pointer)
|
||||
*/
|
||||
chwall_ssidp->chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
if ((chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs) ||
|
||||
(chwall_ssidp->chwall_ssidref == ACM_DEFAULT_LOCAL_SSID)) {
|
||||
printkd("%s: ERROR chwall_ssidref(%x) undefined (>max) or unset (0).\n",
|
||||
__func__, chwall_ssidp->chwall_ssidref);
|
||||
xfree(chwall_ssidp);
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
}
|
||||
(*chwall_ssid) = chwall_ssidp;
|
||||
printkd("%s: determined chwall_ssidref to %x.\n",
|
||||
__func__, chwall_ssidp->chwall_ssidref);
|
||||
return ACM_OK;
|
||||
struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid);
|
||||
traceprintk("%s.\n", __func__);
|
||||
if (chwall_ssidp == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
|
||||
chwall_ssidp->chwall_ssidref =
|
||||
GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
|
||||
if ((chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs)
|
||||
|| (chwall_ssidp->chwall_ssidref == ACM_DEFAULT_LOCAL_SSID))
|
||||
{
|
||||
printkd("%s: ERROR chwall_ssidref(%x) undefined (>max) or unset (0).\n",
|
||||
__func__, chwall_ssidp->chwall_ssidref);
|
||||
xfree(chwall_ssidp);
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
}
|
||||
(*chwall_ssid) = chwall_ssidp;
|
||||
printkd("%s: determined chwall_ssidref to %x.\n",
|
||||
__func__, chwall_ssidp->chwall_ssidref);
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
chwall_free_domain_ssid(void *chwall_ssid)
|
||||
static void chwall_free_domain_ssid(void *chwall_ssid)
|
||||
{
|
||||
traceprintk("%s.\n", __func__);
|
||||
if (chwall_ssid != NULL)
|
||||
xfree(chwall_ssid);
|
||||
return;
|
||||
traceprintk("%s.\n", __func__);
|
||||
if (chwall_ssid != NULL)
|
||||
xfree(chwall_ssid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* dump chinese wall cache; policy read-locked already */
|
||||
static int
|
||||
chwall_dump_policy(u8 *buf, u16 buf_size) {
|
||||
struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
|
||||
int ret = 0;
|
||||
static int chwall_dump_policy(u8 * buf, u32 buf_size)
|
||||
{
|
||||
struct acm_chwall_policy_buffer *chwall_buf =
|
||||
(struct acm_chwall_policy_buffer *) buf;
|
||||
int ret = 0;
|
||||
|
||||
chwall_buf->chwall_max_types = htonl(chwall_bin_pol.max_types);
|
||||
chwall_buf->chwall_max_ssidrefs = htonl(chwall_bin_pol.max_ssidrefs);
|
||||
chwall_buf->policy_code = htonl(ACM_CHINESE_WALL_POLICY);
|
||||
chwall_buf->chwall_ssid_offset = htonl(sizeof(struct acm_chwall_policy_buffer));
|
||||
chwall_buf->chwall_max_conflictsets = htonl(chwall_bin_pol.max_conflictsets);
|
||||
chwall_buf->chwall_conflict_sets_offset =
|
||||
htonl(
|
||||
ntohl(chwall_buf->chwall_ssid_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs *
|
||||
chwall_bin_pol.max_types);
|
||||
if (buf_size < sizeof(struct acm_chwall_policy_buffer))
|
||||
return -EINVAL;
|
||||
|
||||
chwall_buf->chwall_running_types_offset =
|
||||
htonl(
|
||||
ntohl(chwall_buf->chwall_conflict_sets_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets *
|
||||
chwall_bin_pol.max_types);
|
||||
chwall_buf->chwall_max_types = htonl(chwall_bin_pol.max_types);
|
||||
chwall_buf->chwall_max_ssidrefs = htonl(chwall_bin_pol.max_ssidrefs);
|
||||
chwall_buf->policy_code = htonl(ACM_CHINESE_WALL_POLICY);
|
||||
chwall_buf->chwall_ssid_offset =
|
||||
htonl(sizeof(struct acm_chwall_policy_buffer));
|
||||
chwall_buf->chwall_max_conflictsets =
|
||||
htonl(chwall_bin_pol.max_conflictsets);
|
||||
chwall_buf->chwall_conflict_sets_offset =
|
||||
htonl(ntohl(chwall_buf->chwall_ssid_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs *
|
||||
chwall_bin_pol.max_types);
|
||||
chwall_buf->chwall_running_types_offset =
|
||||
htonl(ntohl(chwall_buf->chwall_conflict_sets_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets *
|
||||
chwall_bin_pol.max_types);
|
||||
chwall_buf->chwall_conflict_aggregate_offset =
|
||||
htonl(ntohl(chwall_buf->chwall_running_types_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_types);
|
||||
|
||||
chwall_buf->chwall_conflict_aggregate_offset =
|
||||
htonl(
|
||||
ntohl(chwall_buf->chwall_running_types_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_types);
|
||||
ret = ntohl(chwall_buf->chwall_conflict_aggregate_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_types;
|
||||
|
||||
ret = ntohl(chwall_buf->chwall_conflict_aggregate_offset) +
|
||||
sizeof(domaintype_t) * chwall_bin_pol.max_types;
|
||||
if (buf_size < ret)
|
||||
return -EINVAL;
|
||||
|
||||
/* now copy buffers over */
|
||||
arrcpy16((u16 *)(buf + ntohl(chwall_buf->chwall_ssid_offset)),
|
||||
chwall_bin_pol.ssidrefs,
|
||||
chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types);
|
||||
/* now copy buffers over */
|
||||
arrcpy16((u16 *) (buf + ntohl(chwall_buf->chwall_ssid_offset)),
|
||||
chwall_bin_pol.ssidrefs,
|
||||
chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types);
|
||||
|
||||
arrcpy16((u16 *)(buf + ntohl(chwall_buf->chwall_conflict_sets_offset)),
|
||||
chwall_bin_pol.conflict_sets,
|
||||
chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types);
|
||||
arrcpy16((u16 *) (buf +
|
||||
ntohl(chwall_buf->chwall_conflict_sets_offset)),
|
||||
chwall_bin_pol.conflict_sets,
|
||||
chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types);
|
||||
|
||||
arrcpy16((u16 *)(buf + ntohl(chwall_buf->chwall_running_types_offset)),
|
||||
chwall_bin_pol.running_types,
|
||||
chwall_bin_pol.max_types);
|
||||
arrcpy16((u16 *) (buf +
|
||||
ntohl(chwall_buf->chwall_running_types_offset)),
|
||||
chwall_bin_pol.running_types, chwall_bin_pol.max_types);
|
||||
|
||||
arrcpy16((u16 *)(buf + ntohl(chwall_buf->chwall_conflict_aggregate_offset)),
|
||||
chwall_bin_pol.conflict_aggregate_set,
|
||||
chwall_bin_pol.max_types);
|
||||
return ret;
|
||||
arrcpy16((u16 *) (buf +
|
||||
ntohl(chwall_buf->chwall_conflict_aggregate_offset)),
|
||||
chwall_bin_pol.conflict_aggregate_set,
|
||||
chwall_bin_pol.max_types);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* adapt security state (running_types and conflict_aggregate_set) to all running
|
||||
* domains; chwall_init_state is called when a policy is changed to bring the security
|
||||
* information into a consistent state and to detect violations (return != 0).
|
||||
* from a security point of view, we simulate that all running domains are re-started
|
||||
*/
|
||||
*/
|
||||
static int
|
||||
chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf, domaintype_t *ssidrefs, domaintype_t *conflict_sets,
|
||||
domaintype_t *running_types, domaintype_t *conflict_aggregate_set)
|
||||
chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf,
|
||||
domaintype_t * ssidrefs, domaintype_t * conflict_sets,
|
||||
domaintype_t * running_types,
|
||||
domaintype_t * conflict_aggregate_set)
|
||||
{
|
||||
int violation = 0, i, j;
|
||||
struct chwall_ssid *chwall_ssid;
|
||||
ssidref_t chwall_ssidref;
|
||||
struct domain **pd;
|
||||
int violation = 0, i, j;
|
||||
struct chwall_ssid *chwall_ssid;
|
||||
ssidref_t chwall_ssidref;
|
||||
struct domain **pd;
|
||||
|
||||
write_lock(&domlist_lock);
|
||||
/* go through all domains and adjust policy as if this domain was started now */
|
||||
pd = &domain_list;
|
||||
for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
|
||||
chwall_ssid = GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)(*pd)->ssid);
|
||||
chwall_ssidref = chwall_ssid->chwall_ssidref;
|
||||
traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n",
|
||||
__func__, (*pd)->domain_id, chwall_ssidref);
|
||||
/* a) adjust types ref-count for running domains */
|
||||
for (i=0; i< chwall_buf->chwall_max_types; i++)
|
||||
running_types[i] +=
|
||||
ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i];
|
||||
write_lock(&domlist_lock);
|
||||
/* go through all domains and adjust policy as if this domain was started now */
|
||||
pd = &domain_list;
|
||||
for (pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list)
|
||||
{
|
||||
chwall_ssid =
|
||||
GET_SSIDP(ACM_CHINESE_WALL_POLICY,
|
||||
(struct acm_ssid_domain *) (*pd)->ssid);
|
||||
chwall_ssidref = chwall_ssid->chwall_ssidref;
|
||||
traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n",
|
||||
__func__, (*pd)->domain_id, chwall_ssidref);
|
||||
/* a) adjust types ref-count for running domains */
|
||||
for (i = 0; i < chwall_buf->chwall_max_types; i++)
|
||||
running_types[i] +=
|
||||
ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i];
|
||||
|
||||
/* b) check for conflict */
|
||||
for (i=0; i< chwall_buf->chwall_max_types; i++)
|
||||
if (conflict_aggregate_set[i] &&
|
||||
ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i]) {
|
||||
printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
|
||||
violation = 1;
|
||||
goto out;
|
||||
}
|
||||
/* set violation and break out of the loop */
|
||||
/* c) adapt conflict aggregate set for this domain (notice conflicts) */
|
||||
for (i=0; i<chwall_buf->chwall_max_conflictsets; i++) {
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j=0; j<chwall_buf->chwall_max_types; j++)
|
||||
if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
|
||||
ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j]) {
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j=0; j<chwall_buf->chwall_max_types; j++)
|
||||
if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
|
||||
!ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j])
|
||||
conflict_aggregate_set[j]++;
|
||||
}
|
||||
}
|
||||
/* b) check for conflict */
|
||||
for (i = 0; i < chwall_buf->chwall_max_types; i++)
|
||||
if (conflict_aggregate_set[i] &&
|
||||
ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i])
|
||||
{
|
||||
printk("%s: CHINESE WALL CONFLICT in type %02x.\n",
|
||||
__func__, i);
|
||||
violation = 1;
|
||||
goto out;
|
||||
}
|
||||
/* set violation and break out of the loop */
|
||||
/* c) adapt conflict aggregate set for this domain (notice conflicts) */
|
||||
for (i = 0; i < chwall_buf->chwall_max_conflictsets; i++)
|
||||
{
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j = 0; j < chwall_buf->chwall_max_types; j++)
|
||||
if (conflict_sets[i * chwall_buf->chwall_max_types + j] &&
|
||||
ssidrefs[chwall_ssidref *
|
||||
chwall_buf->chwall_max_types + j])
|
||||
{
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j = 0; j < chwall_buf->chwall_max_types; j++)
|
||||
if (conflict_sets[i * chwall_buf->chwall_max_types + j] &&
|
||||
!ssidrefs[chwall_ssidref *
|
||||
chwall_buf->chwall_max_types + j])
|
||||
conflict_aggregate_set[j]++;
|
||||
}
|
||||
}
|
||||
out:
|
||||
write_unlock(&domlist_lock);
|
||||
return violation;
|
||||
/* returning "violation != 0" means that the currently running set of domains would
|
||||
* not be possible if the new policy had been enforced before starting them; for chinese
|
||||
* wall, this means that the new policy includes at least one conflict set of which
|
||||
* more than one type is currently running */
|
||||
write_unlock(&domlist_lock);
|
||||
return violation;
|
||||
/* returning "violation != 0" means that the currently running set of domains would
|
||||
* not be possible if the new policy had been enforced before starting them; for chinese
|
||||
* wall, this means that the new policy includes at least one conflict set of which
|
||||
* more than one type is currently running */
|
||||
}
|
||||
|
||||
static int
|
||||
chwall_set_policy(u8 *buf, u16 buf_size)
|
||||
{
|
||||
/* policy write-locked already */
|
||||
struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
|
||||
void *ssids = NULL, *conflict_sets = NULL, *running_types = NULL, *conflict_aggregate_set = NULL;
|
||||
|
||||
/* rewrite the policy due to endianess */
|
||||
chwall_buf->policy_code = ntohl(chwall_buf->policy_code);
|
||||
chwall_buf->policy_version = ntohl(chwall_buf->policy_version);
|
||||
chwall_buf->chwall_max_types = ntohl(chwall_buf->chwall_max_types);
|
||||
chwall_buf->chwall_max_ssidrefs = ntohl(chwall_buf->chwall_max_ssidrefs);
|
||||
chwall_buf->chwall_max_conflictsets = ntohl(chwall_buf->chwall_max_conflictsets);
|
||||
chwall_buf->chwall_ssid_offset = ntohl(chwall_buf->chwall_ssid_offset);
|
||||
chwall_buf->chwall_conflict_sets_offset = ntohl(chwall_buf->chwall_conflict_sets_offset);
|
||||
chwall_buf->chwall_running_types_offset = ntohl(chwall_buf->chwall_running_types_offset);
|
||||
chwall_buf->chwall_conflict_aggregate_offset = ntohl(chwall_buf->chwall_conflict_aggregate_offset);
|
||||
|
||||
/* policy type and version checks */
|
||||
if ((chwall_buf->policy_code != ACM_CHINESE_WALL_POLICY) ||
|
||||
(chwall_buf->policy_version != ACM_CHWALL_VERSION))
|
||||
return -EINVAL;
|
||||
|
||||
/* 1. allocate new buffers */
|
||||
ssids = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types*chwall_buf->chwall_max_ssidrefs);
|
||||
conflict_sets = xmalloc_array(domaintype_t, chwall_buf->chwall_max_conflictsets*chwall_buf->chwall_max_types);
|
||||
running_types = xmalloc_array(domaintype_t,chwall_buf->chwall_max_types);
|
||||
conflict_aggregate_set = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
|
||||
|
||||
if ((ssids == NULL)||(conflict_sets == NULL)||(running_types == NULL)||(conflict_aggregate_set == NULL))
|
||||
goto error_free;
|
||||
|
||||
/* 2. set new policy */
|
||||
if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) *
|
||||
chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs > buf_size)
|
||||
goto error_free;
|
||||
arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset,
|
||||
sizeof(domaintype_t),
|
||||
chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs);
|
||||
|
||||
if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) *
|
||||
chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets > buf_size)
|
||||
goto error_free;
|
||||
|
||||
arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset,
|
||||
sizeof(domaintype_t),
|
||||
chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets);
|
||||
|
||||
/* we also use new state buffers since max_types can change */
|
||||
memset(running_types, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
|
||||
memset(conflict_aggregate_set, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
|
||||
|
||||
/* 3. now re-calculate the state for the new policy based on running domains;
|
||||
* this can fail if new policy is conflicting with running domains */
|
||||
if (chwall_init_state(chwall_buf, ssids, conflict_sets, running_types, conflict_aggregate_set)) {
|
||||
printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
|
||||
goto error_free; /* new policy conflicts with running domains */
|
||||
}
|
||||
/* 4. free old policy buffers, replace with new ones */
|
||||
chwall_bin_pol.max_types = chwall_buf->chwall_max_types;
|
||||
chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs;
|
||||
chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets;
|
||||
if (chwall_bin_pol.ssidrefs != NULL)
|
||||
xfree(chwall_bin_pol.ssidrefs);
|
||||
if (chwall_bin_pol.conflict_aggregate_set != NULL)
|
||||
xfree(chwall_bin_pol.conflict_aggregate_set);
|
||||
if (chwall_bin_pol.running_types != NULL)
|
||||
xfree(chwall_bin_pol.running_types);
|
||||
if (chwall_bin_pol.conflict_sets != NULL)
|
||||
xfree(chwall_bin_pol.conflict_sets);
|
||||
chwall_bin_pol.ssidrefs = ssids;
|
||||
chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set;
|
||||
chwall_bin_pol.running_types = running_types;
|
||||
chwall_bin_pol.conflict_sets = conflict_sets;
|
||||
return ACM_OK;
|
||||
|
||||
error_free:
|
||||
printk("%s: ERROR setting policy.\n", __func__);
|
||||
if (ssids != NULL) xfree(ssids);
|
||||
if (conflict_sets != NULL) xfree(conflict_sets);
|
||||
if (running_types != NULL) xfree(running_types);
|
||||
if (conflict_aggregate_set != NULL) xfree(conflict_aggregate_set);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
chwall_dump_stats(u8 *buf, u16 len)
|
||||
static int chwall_set_policy(u8 * buf, u32 buf_size)
|
||||
{
|
||||
/* no stats for Chinese Wall Policy */
|
||||
return 0;
|
||||
/* policy write-locked already */
|
||||
struct acm_chwall_policy_buffer *chwall_buf =
|
||||
(struct acm_chwall_policy_buffer *) buf;
|
||||
void *ssids = NULL, *conflict_sets = NULL, *running_types =
|
||||
NULL, *conflict_aggregate_set = NULL;
|
||||
|
||||
if (buf_size < sizeof(struct acm_chwall_policy_buffer))
|
||||
return -EINVAL;
|
||||
|
||||
/* rewrite the policy due to endianess */
|
||||
chwall_buf->policy_code = ntohl(chwall_buf->policy_code);
|
||||
chwall_buf->policy_version = ntohl(chwall_buf->policy_version);
|
||||
chwall_buf->chwall_max_types = ntohl(chwall_buf->chwall_max_types);
|
||||
chwall_buf->chwall_max_ssidrefs =
|
||||
ntohl(chwall_buf->chwall_max_ssidrefs);
|
||||
chwall_buf->chwall_max_conflictsets =
|
||||
ntohl(chwall_buf->chwall_max_conflictsets);
|
||||
chwall_buf->chwall_ssid_offset = ntohl(chwall_buf->chwall_ssid_offset);
|
||||
chwall_buf->chwall_conflict_sets_offset =
|
||||
ntohl(chwall_buf->chwall_conflict_sets_offset);
|
||||
chwall_buf->chwall_running_types_offset =
|
||||
ntohl(chwall_buf->chwall_running_types_offset);
|
||||
chwall_buf->chwall_conflict_aggregate_offset =
|
||||
ntohl(chwall_buf->chwall_conflict_aggregate_offset);
|
||||
|
||||
/* policy type and version checks */
|
||||
if ((chwall_buf->policy_code != ACM_CHINESE_WALL_POLICY) ||
|
||||
(chwall_buf->policy_version != ACM_CHWALL_VERSION))
|
||||
return -EINVAL;
|
||||
|
||||
/* 1. allocate new buffers */
|
||||
ssids =
|
||||
xmalloc_array(domaintype_t,
|
||||
chwall_buf->chwall_max_types *
|
||||
chwall_buf->chwall_max_ssidrefs);
|
||||
conflict_sets =
|
||||
xmalloc_array(domaintype_t,
|
||||
chwall_buf->chwall_max_conflictsets *
|
||||
chwall_buf->chwall_max_types);
|
||||
running_types =
|
||||
xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
|
||||
conflict_aggregate_set =
|
||||
xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
|
||||
|
||||
if ((ssids == NULL) || (conflict_sets == NULL)
|
||||
|| (running_types == NULL) || (conflict_aggregate_set == NULL))
|
||||
goto error_free;
|
||||
|
||||
/* 2. set new policy */
|
||||
if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) *
|
||||
chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs >
|
||||
buf_size)
|
||||
goto error_free;
|
||||
|
||||
arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset,
|
||||
sizeof(domaintype_t),
|
||||
chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs);
|
||||
|
||||
if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) *
|
||||
chwall_buf->chwall_max_types *
|
||||
chwall_buf->chwall_max_conflictsets > buf_size)
|
||||
goto error_free;
|
||||
|
||||
arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset,
|
||||
sizeof(domaintype_t),
|
||||
chwall_buf->chwall_max_types *
|
||||
chwall_buf->chwall_max_conflictsets);
|
||||
|
||||
/* we also use new state buffers since max_types can change */
|
||||
memset(running_types, 0,
|
||||
sizeof(domaintype_t) * chwall_buf->chwall_max_types);
|
||||
memset(conflict_aggregate_set, 0,
|
||||
sizeof(domaintype_t) * chwall_buf->chwall_max_types);
|
||||
|
||||
/* 3. now re-calculate the state for the new policy based on running domains;
|
||||
* this can fail if new policy is conflicting with running domains */
|
||||
if (chwall_init_state(chwall_buf, ssids,
|
||||
conflict_sets, running_types,
|
||||
conflict_aggregate_set))
|
||||
{
|
||||
printk("%s: New policy conflicts with running domains. Policy load aborted.\n",
|
||||
__func__);
|
||||
goto error_free; /* new policy conflicts with running domains */
|
||||
}
|
||||
/* 4. free old policy buffers, replace with new ones */
|
||||
chwall_bin_pol.max_types = chwall_buf->chwall_max_types;
|
||||
chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs;
|
||||
chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets;
|
||||
if (chwall_bin_pol.ssidrefs != NULL)
|
||||
xfree(chwall_bin_pol.ssidrefs);
|
||||
if (chwall_bin_pol.conflict_aggregate_set != NULL)
|
||||
xfree(chwall_bin_pol.conflict_aggregate_set);
|
||||
if (chwall_bin_pol.running_types != NULL)
|
||||
xfree(chwall_bin_pol.running_types);
|
||||
if (chwall_bin_pol.conflict_sets != NULL)
|
||||
xfree(chwall_bin_pol.conflict_sets);
|
||||
chwall_bin_pol.ssidrefs = ssids;
|
||||
chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set;
|
||||
chwall_bin_pol.running_types = running_types;
|
||||
chwall_bin_pol.conflict_sets = conflict_sets;
|
||||
return ACM_OK;
|
||||
|
||||
error_free:
|
||||
printk("%s: ERROR setting policy.\n", __func__);
|
||||
if (ssids != NULL)
|
||||
xfree(ssids);
|
||||
if (conflict_sets != NULL)
|
||||
xfree(conflict_sets);
|
||||
if (running_types != NULL)
|
||||
xfree(running_types);
|
||||
if (conflict_aggregate_set != NULL)
|
||||
xfree(conflict_aggregate_set);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
chwall_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
|
||||
static int chwall_dump_stats(u8 * buf, u16 len)
|
||||
{
|
||||
/* no stats for Chinese Wall Policy */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chwall_dump_ssid_types(ssidref_t ssidref, u8 * buf, u16 len)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -319,12 +385,14 @@ chwall_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
|
||||
if (chwall_bin_pol.max_types > len)
|
||||
return -EFAULT;
|
||||
|
||||
if (ssidref >= chwall_bin_pol.max_ssidrefs)
|
||||
return -EFAULT;
|
||||
if (ssidref >= chwall_bin_pol.max_ssidrefs)
|
||||
return -EFAULT;
|
||||
|
||||
/* read types for chwall ssidref */
|
||||
for(i=0; i< chwall_bin_pol.max_types; i++) {
|
||||
if (chwall_bin_pol.ssidrefs[ssidref * chwall_bin_pol.max_types + i])
|
||||
for (i = 0; i < chwall_bin_pol.max_types; i++)
|
||||
{
|
||||
if (chwall_bin_pol.
|
||||
ssidrefs[ssidref * chwall_bin_pol.max_types + i])
|
||||
buf[i] = 1;
|
||||
else
|
||||
buf[i] = 0;
|
||||
@@ -336,198 +404,239 @@ chwall_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
|
||||
* Authorization functions
|
||||
***************************/
|
||||
|
||||
|
||||
/* -------- DOMAIN OPERATION HOOKS -----------*/
|
||||
|
||||
static int
|
||||
chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
|
||||
static int chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
|
||||
{
|
||||
ssidref_t chwall_ssidref;
|
||||
int i,j;
|
||||
traceprintk("%s.\n", __func__);
|
||||
ssidref_t chwall_ssidref;
|
||||
int i, j;
|
||||
traceprintk("%s.\n", __func__);
|
||||
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID) {
|
||||
printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n", __func__);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED; /* catching and indicating config error */
|
||||
}
|
||||
if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs) {
|
||||
printk("%s: ERROR chwall_ssidref > max(%x).\n",
|
||||
__func__, chwall_bin_pol.max_ssidrefs-1);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
/* A: chinese wall check for conflicts */
|
||||
for (i=0; i< chwall_bin_pol.max_types; i++)
|
||||
if (chwall_bin_pol.conflict_aggregate_set[i] &&
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i]) {
|
||||
printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID)
|
||||
{
|
||||
printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n",
|
||||
__func__);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED; /* catching and indicating config error */
|
||||
}
|
||||
if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs)
|
||||
{
|
||||
printk("%s: ERROR chwall_ssidref > max(%x).\n",
|
||||
__func__, chwall_bin_pol.max_ssidrefs - 1);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
/* A: chinese wall check for conflicts */
|
||||
for (i = 0; i < chwall_bin_pol.max_types; i++)
|
||||
if (chwall_bin_pol.conflict_aggregate_set[i] &&
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + i])
|
||||
{
|
||||
printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
/* B: chinese wall conflict set adjustment (so that other
|
||||
* other domains simultaneously created are evaluated against this new set)*/
|
||||
for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
!chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]++;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
/* B: chinese wall conflict set adjustment (so that other
|
||||
* other domains simultaneously created are evaluated against this new set)*/
|
||||
for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
|
||||
{
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
{
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& !chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]++;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
|
||||
static void
|
||||
chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
|
||||
static void chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
|
||||
{
|
||||
int i,j;
|
||||
ssidref_t chwall_ssidref;
|
||||
traceprintk("%s.\n", __func__);
|
||||
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
/* adjust types ref-count for running domains */
|
||||
for (i=0; i< chwall_bin_pol.max_types; i++)
|
||||
chwall_bin_pol.running_types[i] +=
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
|
||||
if (domid) {
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return;
|
||||
}
|
||||
/* Xen does not call pre-create hook for DOM0;
|
||||
* to consider type conflicts of any domain with DOM0, we need
|
||||
* to adjust the conflict_aggregate for DOM0 here the same way it
|
||||
* is done for non-DOM0 domains in the pre-hook */
|
||||
printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n",
|
||||
__func__, ssidref, chwall_ssidref);
|
||||
int i, j;
|
||||
ssidref_t chwall_ssidref;
|
||||
traceprintk("%s.\n", __func__);
|
||||
|
||||
/* chinese wall conflict set adjustment (so that other
|
||||
* other domains simultaneously created are evaluated against this new set)*/
|
||||
for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
!chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]++;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return;
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
/* adjust types ref-count for running domains */
|
||||
for (i = 0; i < chwall_bin_pol.max_types; i++)
|
||||
chwall_bin_pol.running_types[i] +=
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + i];
|
||||
if (domid)
|
||||
{
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return;
|
||||
}
|
||||
/* Xen does not call pre-create hook for DOM0;
|
||||
* to consider type conflicts of any domain with DOM0, we need
|
||||
* to adjust the conflict_aggregate for DOM0 here the same way it
|
||||
* is done for non-DOM0 domains in the pre-hook */
|
||||
printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n",
|
||||
__func__, ssidref, chwall_ssidref);
|
||||
|
||||
/* chinese wall conflict set adjustment (so that other
|
||||
* other domains simultaneously created are evaluated against this new set)*/
|
||||
for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
|
||||
{
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
{
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& !chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]++;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
chwall_fail_domain_create(void *subject_ssid, ssidref_t ssidref)
|
||||
{
|
||||
int i, j;
|
||||
ssidref_t chwall_ssidref;
|
||||
traceprintk("%s.\n", __func__);
|
||||
int i, j;
|
||||
ssidref_t chwall_ssidref;
|
||||
traceprintk("%s.\n", __func__);
|
||||
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
/* roll-back: re-adjust conflicting types aggregate */
|
||||
for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
!chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]--;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
|
||||
/* roll-back: re-adjust conflicting types aggregate */
|
||||
for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
|
||||
{
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
{
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& !chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]--;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chwall_post_domain_destroy(void *object_ssid, domid_t id)
|
||||
static void chwall_post_domain_destroy(void *object_ssid, domid_t id)
|
||||
{
|
||||
int i,j;
|
||||
struct chwall_ssid *chwall_ssidp =
|
||||
GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)object_ssid);
|
||||
ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref;
|
||||
int i, j;
|
||||
struct chwall_ssid *chwall_ssidp = GET_SSIDP(ACM_CHINESE_WALL_POLICY,
|
||||
(struct acm_ssid_domain *)
|
||||
object_ssid);
|
||||
ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref;
|
||||
|
||||
traceprintk("%s.\n", __func__);
|
||||
traceprintk("%s.\n", __func__);
|
||||
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
/* adjust running types set */
|
||||
for (i=0; i< chwall_bin_pol.max_types; i++)
|
||||
chwall_bin_pol.running_types[i] -=
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
/* adjust running types set */
|
||||
for (i = 0; i < chwall_bin_pol.max_types; i++)
|
||||
chwall_bin_pol.running_types[i] -=
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + i];
|
||||
|
||||
/* roll-back: re-adjust conflicting types aggregate */
|
||||
for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j=0; j<chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
|
||||
!chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]--;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return;
|
||||
/* roll-back: re-adjust conflicting types aggregate */
|
||||
for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
|
||||
{
|
||||
int common = 0;
|
||||
/* check if conflict_set_i and ssidref have common types */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
{
|
||||
common = 1;
|
||||
break;
|
||||
}
|
||||
if (common == 0)
|
||||
continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
|
||||
/* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
|
||||
for (j = 0; j < chwall_bin_pol.max_types; j++)
|
||||
if (chwall_bin_pol.
|
||||
conflict_sets[i * chwall_bin_pol.max_types + j]
|
||||
&& !chwall_bin_pol.ssidrefs[chwall_ssidref *
|
||||
chwall_bin_pol.max_types + j])
|
||||
chwall_bin_pol.conflict_aggregate_set[j]--;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return;
|
||||
}
|
||||
|
||||
struct acm_operations acm_chinesewall_ops = {
|
||||
/* policy management services */
|
||||
.init_domain_ssid = chwall_init_domain_ssid,
|
||||
.free_domain_ssid = chwall_free_domain_ssid,
|
||||
.dump_binary_policy = chwall_dump_policy,
|
||||
.set_binary_policy = chwall_set_policy,
|
||||
.dump_statistics = chwall_dump_stats,
|
||||
.dump_ssid_types = chwall_dump_ssid_types,
|
||||
/* domain management control hooks */
|
||||
.pre_domain_create = chwall_pre_domain_create,
|
||||
.post_domain_create = chwall_post_domain_create,
|
||||
.fail_domain_create = chwall_fail_domain_create,
|
||||
.post_domain_destroy = chwall_post_domain_destroy,
|
||||
/* event channel control hooks */
|
||||
.pre_eventchannel_unbound = NULL,
|
||||
.fail_eventchannel_unbound = NULL,
|
||||
.pre_eventchannel_interdomain = NULL,
|
||||
.fail_eventchannel_interdomain = NULL,
|
||||
/* grant table control hooks */
|
||||
.pre_grant_map_ref = NULL,
|
||||
.fail_grant_map_ref = NULL,
|
||||
.pre_grant_setup = NULL,
|
||||
.fail_grant_setup = NULL,
|
||||
/* policy management services */
|
||||
.init_domain_ssid = chwall_init_domain_ssid,
|
||||
.free_domain_ssid = chwall_free_domain_ssid,
|
||||
.dump_binary_policy = chwall_dump_policy,
|
||||
.set_binary_policy = chwall_set_policy,
|
||||
.dump_statistics = chwall_dump_stats,
|
||||
.dump_ssid_types = chwall_dump_ssid_types,
|
||||
/* domain management control hooks */
|
||||
.pre_domain_create = chwall_pre_domain_create,
|
||||
.post_domain_create = chwall_post_domain_create,
|
||||
.fail_domain_create = chwall_fail_domain_create,
|
||||
.post_domain_destroy = chwall_post_domain_destroy,
|
||||
/* event channel control hooks */
|
||||
.pre_eventchannel_unbound = NULL,
|
||||
.fail_eventchannel_unbound = NULL,
|
||||
.pre_eventchannel_interdomain = NULL,
|
||||
.fail_eventchannel_interdomain = NULL,
|
||||
/* grant table control hooks */
|
||||
.pre_grant_map_ref = NULL,
|
||||
.fail_grant_map_ref = NULL,
|
||||
.pre_grant_setup = NULL,
|
||||
.fail_grant_setup = NULL,
|
||||
/* generic domain-requested decision hooks */
|
||||
.sharing = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
+100
-93
@@ -47,7 +47,7 @@ void acm_init_chwall_policy(void);
|
||||
void acm_init_ste_policy(void);
|
||||
|
||||
extern struct acm_operations acm_chinesewall_ops,
|
||||
acm_simple_type_enforcement_ops, acm_null_ops;
|
||||
acm_simple_type_enforcement_ops, acm_null_ops;
|
||||
|
||||
/* global ops structs called by the hooks */
|
||||
struct acm_operations *acm_primary_ops = NULL;
|
||||
@@ -66,7 +66,7 @@ void acm_set_endian(void)
|
||||
u32 test = 1;
|
||||
if (*((u8 *)&test) == 1)
|
||||
{
|
||||
printk("ACM module running in LITTLE ENDIAN.\n");
|
||||
printk("ACM module running in LITTLE ENDIAN.\n");
|
||||
little_endian = 1;
|
||||
}
|
||||
else
|
||||
@@ -80,10 +80,10 @@ void acm_set_endian(void)
|
||||
static void
|
||||
acm_init_binary_policy(void *primary, void *secondary)
|
||||
{
|
||||
acm_bin_pol.primary_policy_code = 0;
|
||||
acm_bin_pol.secondary_policy_code = 0;
|
||||
acm_bin_pol.primary_binary_policy = primary;
|
||||
acm_bin_pol.secondary_binary_policy = secondary;
|
||||
acm_bin_pol.primary_policy_code = 0;
|
||||
acm_bin_pol.secondary_policy_code = 0;
|
||||
acm_bin_pol.primary_binary_policy = primary;
|
||||
acm_bin_pol.secondary_binary_policy = secondary;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -96,7 +96,7 @@ acm_setup(unsigned int *initrdidx,
|
||||
int rc = ACM_OK;
|
||||
|
||||
if (mbi->mods_count > 1)
|
||||
*initrdidx = 1;
|
||||
*initrdidx = 1;
|
||||
|
||||
/*
|
||||
* Try all modules and see whichever could be the binary policy.
|
||||
@@ -115,14 +115,14 @@ acm_setup(unsigned int *initrdidx,
|
||||
#error Architecture unsupported by sHype
|
||||
#endif
|
||||
_policy_len = mod[i].mod_end - mod[i].mod_start;
|
||||
if (_policy_len < sizeof(struct acm_policy_buffer))
|
||||
continue; /* not a policy */
|
||||
if (_policy_len < sizeof(struct acm_policy_buffer))
|
||||
continue; /* not a policy */
|
||||
|
||||
pol = (struct acm_policy_buffer *)_policy_start;
|
||||
if (ntohl(pol->magic) == ACM_MAGIC)
|
||||
{
|
||||
rc = acm_set_policy((void *)_policy_start,
|
||||
(u16)_policy_len,
|
||||
(u32)_policy_len,
|
||||
0);
|
||||
if (rc == ACM_OK)
|
||||
{
|
||||
@@ -145,7 +145,7 @@ acm_setup(unsigned int *initrdidx,
|
||||
}
|
||||
else
|
||||
{
|
||||
printk("Invalid policy. %d.th module line.\n", i+1);
|
||||
printk("Invalid policy. %d.th module line.\n", i+1);
|
||||
}
|
||||
} /* end if a binary policy definition, i.e., (ntohl(pol->magic) == ACM_MAGIC ) */
|
||||
}
|
||||
@@ -158,10 +158,10 @@ acm_init(unsigned int *initrdidx,
|
||||
const multiboot_info_t *mbi,
|
||||
unsigned long initial_images_start)
|
||||
{
|
||||
int ret = ACM_OK;
|
||||
int ret = ACM_OK;
|
||||
|
||||
acm_set_endian();
|
||||
write_lock(&acm_bin_pol_rwlock);
|
||||
write_lock(&acm_bin_pol_rwlock);
|
||||
acm_init_binary_policy(NULL, NULL);
|
||||
|
||||
/* set primary policy component */
|
||||
@@ -170,14 +170,14 @@ acm_init(unsigned int *initrdidx,
|
||||
|
||||
case ACM_CHINESE_WALL_POLICY:
|
||||
acm_init_chwall_policy();
|
||||
acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
|
||||
acm_primary_ops = &acm_chinesewall_ops;
|
||||
acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
|
||||
acm_primary_ops = &acm_chinesewall_ops;
|
||||
break;
|
||||
|
||||
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
|
||||
acm_init_ste_policy();
|
||||
acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
|
||||
acm_primary_ops = &acm_simple_type_enforcement_ops;
|
||||
acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
|
||||
acm_primary_ops = &acm_simple_type_enforcement_ops;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -190,9 +190,9 @@ acm_init(unsigned int *initrdidx,
|
||||
/* secondary policy component part */
|
||||
switch ((ACM_USE_SECURITY_POLICY) >> 4) {
|
||||
case ACM_NULL_POLICY:
|
||||
acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
|
||||
acm_secondary_ops = &acm_null_ops;
|
||||
break;
|
||||
acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
|
||||
acm_secondary_ops = &acm_null_ops;
|
||||
break;
|
||||
|
||||
case ACM_CHINESE_WALL_POLICY:
|
||||
if (acm_bin_pol.primary_policy_code == ACM_CHINESE_WALL_POLICY)
|
||||
@@ -200,9 +200,9 @@ acm_init(unsigned int *initrdidx,
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
acm_init_chwall_policy();
|
||||
acm_init_chwall_policy();
|
||||
acm_bin_pol.secondary_policy_code = ACM_CHINESE_WALL_POLICY;
|
||||
acm_secondary_ops = &acm_chinesewall_ops;
|
||||
acm_secondary_ops = &acm_chinesewall_ops;
|
||||
break;
|
||||
|
||||
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
|
||||
@@ -211,9 +211,9 @@ acm_init(unsigned int *initrdidx,
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
acm_init_ste_policy();
|
||||
acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
|
||||
acm_secondary_ops = &acm_simple_type_enforcement_ops;
|
||||
acm_init_ste_policy();
|
||||
acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
|
||||
acm_secondary_ops = &acm_simple_type_enforcement_ops;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -222,96 +222,103 @@ acm_init(unsigned int *initrdidx,
|
||||
}
|
||||
|
||||
out:
|
||||
write_unlock(&acm_bin_pol_rwlock);
|
||||
write_unlock(&acm_bin_pol_rwlock);
|
||||
|
||||
if (ret != ACM_OK)
|
||||
if (ret != ACM_OK)
|
||||
{
|
||||
printk("%s: Error setting policies.\n", __func__);
|
||||
printk("%s: Error initializing policies.\n", __func__);
|
||||
/* here one could imagine a clean panic */
|
||||
return -EINVAL;
|
||||
}
|
||||
acm_setup(initrdidx, mbi, initial_images_start);
|
||||
printk("%s: Enforcing Primary %s, Secondary %s.\n", __func__,
|
||||
ACM_POLICY_NAME(acm_bin_pol.primary_policy_code),
|
||||
return -EINVAL;
|
||||
}
|
||||
if (acm_setup(initrdidx, mbi, initial_images_start) != ACM_OK)
|
||||
{
|
||||
printk("%s: Error loading policy at boot time.\n", __func__);
|
||||
/* ignore, just continue with the minimal hardcoded startup policy */
|
||||
}
|
||||
printk("%s: Enforcing Primary %s, Secondary %s.\n", __func__,
|
||||
ACM_POLICY_NAME(acm_bin_pol.primary_policy_code),
|
||||
ACM_POLICY_NAME(acm_bin_pol.secondary_policy_code));
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
|
||||
{
|
||||
struct acm_ssid_domain *ssid;
|
||||
struct domain *subj = find_domain_by_id(id);
|
||||
int ret1, ret2;
|
||||
|
||||
if (subj == NULL)
|
||||
struct acm_ssid_domain *ssid;
|
||||
struct domain *subj = find_domain_by_id(id);
|
||||
int ret1, ret2;
|
||||
|
||||
if (subj == NULL)
|
||||
{
|
||||
printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
|
||||
return ACM_NULL_POINTER_ERROR;
|
||||
}
|
||||
if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
|
||||
return ACM_NULL_POINTER_ERROR;
|
||||
}
|
||||
if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
|
||||
ssid->datatype = DOMAIN;
|
||||
ssid->subject = subj;
|
||||
ssid->domainid = subj->domain_id;
|
||||
ssid->primary_ssid = NULL;
|
||||
ssid->secondary_ssid = NULL;
|
||||
ssid->datatype = DOMAIN;
|
||||
ssid->subject = subj;
|
||||
ssid->domainid = subj->domain_id;
|
||||
ssid->primary_ssid = NULL;
|
||||
ssid->secondary_ssid = NULL;
|
||||
|
||||
if (ACM_USE_SECURITY_POLICY != ACM_NULL_POLICY)
|
||||
ssid->ssidref = ssidref;
|
||||
else
|
||||
ssid->ssidref = ACM_DEFAULT_SSID;
|
||||
if (ACM_USE_SECURITY_POLICY != ACM_NULL_POLICY)
|
||||
ssid->ssidref = ssidref;
|
||||
else
|
||||
ssid->ssidref = ACM_DEFAULT_SSID;
|
||||
|
||||
subj->ssid = ssid;
|
||||
/* now fill in primary and secondary parts; we only get here through hooks */
|
||||
if (acm_primary_ops->init_domain_ssid != NULL)
|
||||
ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
|
||||
else
|
||||
ret1 = ACM_OK;
|
||||
subj->ssid = ssid;
|
||||
/* now fill in primary and secondary parts; we only get here through hooks */
|
||||
if (acm_primary_ops->init_domain_ssid != NULL)
|
||||
ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
|
||||
else
|
||||
ret1 = ACM_OK;
|
||||
|
||||
if (acm_secondary_ops->init_domain_ssid != NULL)
|
||||
ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
|
||||
else
|
||||
ret2 = ACM_OK;
|
||||
if (acm_secondary_ops->init_domain_ssid != NULL)
|
||||
ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
|
||||
else
|
||||
ret2 = ACM_OK;
|
||||
|
||||
if ((ret1 != ACM_OK) || (ret2 != ACM_OK))
|
||||
if ((ret1 != ACM_OK) || (ret2 != ACM_OK))
|
||||
{
|
||||
printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
|
||||
__func__, subj->domain_id);
|
||||
acm_free_domain_ssid(ssid);
|
||||
put_domain(subj);
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
}
|
||||
printk("%s: assigned domain %x the ssidref=%x.\n",
|
||||
printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
|
||||
__func__, subj->domain_id);
|
||||
acm_free_domain_ssid(ssid);
|
||||
put_domain(subj);
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
}
|
||||
printk("%s: assigned domain %x the ssidref=%x.\n",
|
||||
__func__, id, ssid->ssidref);
|
||||
put_domain(subj);
|
||||
return ACM_OK;
|
||||
put_domain(subj);
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
void
|
||||
acm_free_domain_ssid(struct acm_ssid_domain *ssid)
|
||||
{
|
||||
domid_t id;
|
||||
/* domain is already gone, just ssid is left */
|
||||
if (ssid == NULL)
|
||||
return;
|
||||
|
||||
/* domain is already gone, just ssid is left */
|
||||
if (ssid == NULL)
|
||||
{
|
||||
printk("%s: ACM_NULL_POINTER ERROR.\n", __func__);
|
||||
return ACM_NULL_POINTER_ERROR;
|
||||
}
|
||||
id = ssid->domainid;
|
||||
ssid->subject = NULL;
|
||||
|
||||
if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
|
||||
acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
|
||||
ssid->primary_ssid = NULL;
|
||||
if (acm_secondary_ops->free_domain_ssid != NULL)
|
||||
acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
|
||||
ssid->secondary_ssid = NULL;
|
||||
xfree(ssid);
|
||||
printkd("%s: Freed individual domain ssid (domain=%02x).\n",
|
||||
ssid->subject = NULL;
|
||||
if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
|
||||
acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
|
||||
ssid->primary_ssid = NULL;
|
||||
if (acm_secondary_ops->free_domain_ssid != NULL)
|
||||
acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
|
||||
ssid->secondary_ssid = NULL;
|
||||
xfree(ssid);
|
||||
printkd("%s: Freed individual domain ssid (domain=%02x).\n",
|
||||
__func__, id);
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
+43
-32
@@ -11,37 +11,38 @@
|
||||
* published by the Free Software Foundation, version 2 of the
|
||||
* License.
|
||||
*/
|
||||
|
||||
#include <acm/acm_hooks.h>
|
||||
|
||||
static int
|
||||
null_init_domain_ssid(void **ssid, ssidref_t ssidref)
|
||||
{
|
||||
return ACM_OK;
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
null_free_domain_ssid(void *ssid)
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
null_dump_binary_policy(u8 *buf, u16 buf_size)
|
||||
{
|
||||
return 0;
|
||||
null_dump_binary_policy(u8 *buf, u32 buf_size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
null_set_binary_policy(u8 *buf, u16 buf_size)
|
||||
{
|
||||
return ACM_OK;
|
||||
null_set_binary_policy(u8 *buf, u32 buf_size)
|
||||
{
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
null_dump_stats(u8 *buf, u16 buf_size)
|
||||
{
|
||||
/* no stats for NULL policy */
|
||||
return 0;
|
||||
/* no stats for NULL policy */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -54,25 +55,35 @@ null_dump_ssid_types(ssidref_t ssidref, u8 *buffer, u16 buf_size)
|
||||
|
||||
/* now define the hook structure similarly to LSM */
|
||||
struct acm_operations acm_null_ops = {
|
||||
.init_domain_ssid = null_init_domain_ssid,
|
||||
.free_domain_ssid = null_free_domain_ssid,
|
||||
.dump_binary_policy = null_dump_binary_policy,
|
||||
.set_binary_policy = null_set_binary_policy,
|
||||
.dump_statistics = null_dump_stats,
|
||||
.dump_ssid_types = null_dump_ssid_types,
|
||||
/* domain management control hooks */
|
||||
.pre_domain_create = NULL,
|
||||
.post_domain_create = NULL,
|
||||
.fail_domain_create = NULL,
|
||||
.post_domain_destroy = NULL,
|
||||
/* event channel control hooks */
|
||||
.pre_eventchannel_unbound = NULL,
|
||||
.fail_eventchannel_unbound = NULL,
|
||||
.pre_eventchannel_interdomain = NULL,
|
||||
.fail_eventchannel_interdomain = NULL,
|
||||
/* grant table control hooks */
|
||||
.pre_grant_map_ref = NULL,
|
||||
.fail_grant_map_ref = NULL,
|
||||
.pre_grant_setup = NULL,
|
||||
.fail_grant_setup = NULL
|
||||
.init_domain_ssid = null_init_domain_ssid,
|
||||
.free_domain_ssid = null_free_domain_ssid,
|
||||
.dump_binary_policy = null_dump_binary_policy,
|
||||
.set_binary_policy = null_set_binary_policy,
|
||||
.dump_statistics = null_dump_stats,
|
||||
.dump_ssid_types = null_dump_ssid_types,
|
||||
/* domain management control hooks */
|
||||
.pre_domain_create = NULL,
|
||||
.post_domain_create = NULL,
|
||||
.fail_domain_create = NULL,
|
||||
.post_domain_destroy = NULL,
|
||||
/* event channel control hooks */
|
||||
.pre_eventchannel_unbound = NULL,
|
||||
.fail_eventchannel_unbound = NULL,
|
||||
.pre_eventchannel_interdomain = NULL,
|
||||
.fail_eventchannel_interdomain = NULL,
|
||||
/* grant table control hooks */
|
||||
.pre_grant_map_ref = NULL,
|
||||
.fail_grant_map_ref = NULL,
|
||||
.pre_grant_setup = NULL,
|
||||
.fail_grant_setup = NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
+187
-155
@@ -32,165 +32,166 @@
|
||||
#include <acm/acm_endian.h>
|
||||
|
||||
int
|
||||
acm_set_policy(void *buf, u16 buf_size, int isuserbuffer)
|
||||
acm_set_policy(void *buf, u32 buf_size, int isuserbuffer)
|
||||
{
|
||||
u8 *policy_buffer = NULL;
|
||||
struct acm_policy_buffer *pol;
|
||||
|
||||
u8 *policy_buffer = NULL;
|
||||
struct acm_policy_buffer *pol;
|
||||
|
||||
if (buf_size < sizeof(struct acm_policy_buffer))
|
||||
return -EFAULT;
|
||||
return -EFAULT;
|
||||
|
||||
/* 1. copy buffer from domain */
|
||||
if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
/* 1. copy buffer from domain */
|
||||
if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (isuserbuffer) {
|
||||
if (copy_from_user(policy_buffer, buf, buf_size))
|
||||
if (isuserbuffer) {
|
||||
if (copy_from_user(policy_buffer, buf, buf_size))
|
||||
{
|
||||
printk("%s: Error copying!\n",__func__);
|
||||
goto error_free;
|
||||
}
|
||||
} else
|
||||
memcpy(policy_buffer, buf, buf_size);
|
||||
printk("%s: Error copying!\n",__func__);
|
||||
goto error_free;
|
||||
}
|
||||
} else
|
||||
memcpy(policy_buffer, buf, buf_size);
|
||||
|
||||
/* 2. some sanity checking */
|
||||
pol = (struct acm_policy_buffer *)policy_buffer;
|
||||
/* 2. some sanity checking */
|
||||
pol = (struct acm_policy_buffer *)policy_buffer;
|
||||
|
||||
if ((ntohl(pol->magic) != ACM_MAGIC) ||
|
||||
(ntohl(pol->policy_version) != ACM_POLICY_VERSION) ||
|
||||
(ntohl(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) ||
|
||||
(ntohl(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code))
|
||||
if ((ntohl(pol->magic) != ACM_MAGIC) ||
|
||||
(ntohl(pol->policy_version) != ACM_POLICY_VERSION) ||
|
||||
(ntohl(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) ||
|
||||
(ntohl(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code))
|
||||
{
|
||||
printkd("%s: Wrong policy magics or versions!\n", __func__);
|
||||
goto error_free;
|
||||
}
|
||||
if (buf_size != ntohl(pol->len))
|
||||
printkd("%s: Wrong policy magics or versions!\n", __func__);
|
||||
goto error_free;
|
||||
}
|
||||
if (buf_size != ntohl(pol->len))
|
||||
{
|
||||
printk("%s: ERROR in buf size.\n", __func__);
|
||||
goto error_free;
|
||||
}
|
||||
printk("%s: ERROR in buf size.\n", __func__);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
/* get bin_policy lock and rewrite policy (release old one) */
|
||||
write_lock(&acm_bin_pol_rwlock);
|
||||
/* get bin_policy lock and rewrite policy (release old one) */
|
||||
write_lock(&acm_bin_pol_rwlock);
|
||||
|
||||
/* 3. set primary policy data */
|
||||
if (acm_primary_ops->set_binary_policy(buf + ntohl(pol->primary_buffer_offset),
|
||||
ntohl(pol->secondary_buffer_offset) -
|
||||
ntohl(pol->primary_buffer_offset)))
|
||||
goto error_lock_free;
|
||||
/* 3. set primary policy data */
|
||||
if (acm_primary_ops->set_binary_policy(buf + ntohl(pol->primary_buffer_offset),
|
||||
ntohl(pol->secondary_buffer_offset) -
|
||||
ntohl(pol->primary_buffer_offset)))
|
||||
goto error_lock_free;
|
||||
|
||||
/* 4. set secondary policy data */
|
||||
if (acm_secondary_ops->set_binary_policy(buf + ntohl(pol->secondary_buffer_offset),
|
||||
ntohl(pol->len) -
|
||||
ntohl(pol->secondary_buffer_offset)))
|
||||
goto error_lock_free;
|
||||
/* 4. set secondary policy data */
|
||||
if (acm_secondary_ops->set_binary_policy(buf + ntohl(pol->secondary_buffer_offset),
|
||||
ntohl(pol->len) -
|
||||
ntohl(pol->secondary_buffer_offset)))
|
||||
goto error_lock_free;
|
||||
|
||||
write_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(policy_buffer);
|
||||
return ACM_OK;
|
||||
write_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(policy_buffer);
|
||||
return ACM_OK;
|
||||
|
||||
error_lock_free:
|
||||
write_unlock(&acm_bin_pol_rwlock);
|
||||
write_unlock(&acm_bin_pol_rwlock);
|
||||
error_free:
|
||||
printk("%s: Error setting policy.\n", __func__);
|
||||
printk("%s: Error setting policy.\n", __func__);
|
||||
xfree(policy_buffer);
|
||||
return -EFAULT;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int
|
||||
acm_get_policy(void *buf, u16 buf_size)
|
||||
{
|
||||
u8 *policy_buffer;
|
||||
int ret;
|
||||
struct acm_policy_buffer *bin_pol;
|
||||
|
||||
acm_get_policy(void *buf, u32 buf_size)
|
||||
{
|
||||
u8 *policy_buffer;
|
||||
int ret;
|
||||
struct acm_policy_buffer *bin_pol;
|
||||
|
||||
if (buf_size < sizeof(struct acm_policy_buffer))
|
||||
return -EFAULT;
|
||||
return -EFAULT;
|
||||
|
||||
if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
|
||||
bin_pol = (struct acm_policy_buffer *)policy_buffer;
|
||||
bin_pol->magic = htonl(ACM_MAGIC);
|
||||
bin_pol->primary_policy_code = htonl(acm_bin_pol.primary_policy_code);
|
||||
bin_pol->secondary_policy_code = htonl(acm_bin_pol.secondary_policy_code);
|
||||
bin_pol = (struct acm_policy_buffer *)policy_buffer;
|
||||
bin_pol->magic = htonl(ACM_MAGIC);
|
||||
bin_pol->primary_policy_code = htonl(acm_bin_pol.primary_policy_code);
|
||||
bin_pol->secondary_policy_code = htonl(acm_bin_pol.secondary_policy_code);
|
||||
|
||||
bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
|
||||
bin_pol->primary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
bin_pol->secondary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
|
||||
bin_pol->primary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
bin_pol->secondary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
|
||||
ret = acm_primary_ops->dump_binary_policy (policy_buffer + ntohl(bin_pol->primary_buffer_offset),
|
||||
buf_size - ntohl(bin_pol->primary_buffer_offset));
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
ret = acm_primary_ops->dump_binary_policy (policy_buffer + ntohl(bin_pol->primary_buffer_offset),
|
||||
buf_size - ntohl(bin_pol->primary_buffer_offset));
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
|
||||
bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
|
||||
bin_pol->secondary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
|
||||
bin_pol->secondary_buffer_offset = htonl(ntohl(bin_pol->len));
|
||||
|
||||
ret = acm_secondary_ops->dump_binary_policy(policy_buffer + ntohl(bin_pol->secondary_buffer_offset),
|
||||
buf_size - ntohl(bin_pol->secondary_buffer_offset));
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
ret = acm_secondary_ops->dump_binary_policy(policy_buffer + ntohl(bin_pol->secondary_buffer_offset),
|
||||
buf_size - ntohl(bin_pol->secondary_buffer_offset));
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
|
||||
bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
|
||||
if (copy_to_user(buf, policy_buffer, ntohl(bin_pol->len)))
|
||||
goto error_free_unlock;
|
||||
bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
|
||||
if (copy_to_user(buf, policy_buffer, ntohl(bin_pol->len)))
|
||||
goto error_free_unlock;
|
||||
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(policy_buffer);
|
||||
return ACM_OK;
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(policy_buffer);
|
||||
return ACM_OK;
|
||||
|
||||
error_free_unlock:
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
printk("%s: Error getting policy.\n", __func__);
|
||||
xfree(policy_buffer);
|
||||
return -EFAULT;
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
printk("%s: Error getting policy.\n", __func__);
|
||||
xfree(policy_buffer);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int
|
||||
acm_dump_statistics(void *buf, u16 buf_size)
|
||||
{
|
||||
{
|
||||
/* send stats to user space */
|
||||
u8 *stats_buffer;
|
||||
int len1, len2;
|
||||
struct acm_stats_buffer acm_stats;
|
||||
u8 *stats_buffer;
|
||||
int len1, len2;
|
||||
struct acm_stats_buffer acm_stats;
|
||||
|
||||
if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
|
||||
len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer),
|
||||
buf_size - sizeof(struct acm_stats_buffer));
|
||||
if (len1 < 0)
|
||||
goto error_lock_free;
|
||||
|
||||
len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1,
|
||||
buf_size - sizeof(struct acm_stats_buffer) - len1);
|
||||
if (len2 < 0)
|
||||
goto error_lock_free;
|
||||
len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer),
|
||||
buf_size - sizeof(struct acm_stats_buffer));
|
||||
if (len1 < 0)
|
||||
goto error_lock_free;
|
||||
|
||||
len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1,
|
||||
buf_size - sizeof(struct acm_stats_buffer) - len1);
|
||||
if (len2 < 0)
|
||||
goto error_lock_free;
|
||||
|
||||
acm_stats.magic = htonl(ACM_MAGIC);
|
||||
acm_stats.primary_policy_code = htonl(acm_bin_pol.primary_policy_code);
|
||||
acm_stats.secondary_policy_code = htonl(acm_bin_pol.secondary_policy_code);
|
||||
acm_stats.primary_stats_offset = htonl(sizeof(struct acm_stats_buffer));
|
||||
acm_stats.secondary_stats_offset = htonl(sizeof(struct acm_stats_buffer) + len1);
|
||||
acm_stats.len = htonl(sizeof(struct acm_stats_buffer) + len1 + len2);
|
||||
memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
|
||||
acm_stats.magic = htonl(ACM_MAGIC);
|
||||
acm_stats.primary_policy_code = htonl(acm_bin_pol.primary_policy_code);
|
||||
acm_stats.secondary_policy_code = htonl(acm_bin_pol.secondary_policy_code);
|
||||
acm_stats.primary_stats_offset = htonl(sizeof(struct acm_stats_buffer));
|
||||
acm_stats.secondary_stats_offset = htonl(sizeof(struct acm_stats_buffer) + len1);
|
||||
acm_stats.len = htonl(sizeof(struct acm_stats_buffer) + len1 + len2);
|
||||
|
||||
if (copy_to_user(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2))
|
||||
goto error_lock_free;
|
||||
memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
|
||||
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(stats_buffer);
|
||||
return ACM_OK;
|
||||
if (copy_to_user(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2))
|
||||
goto error_lock_free;
|
||||
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(stats_buffer);
|
||||
return ACM_OK;
|
||||
|
||||
error_lock_free:
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(stats_buffer);
|
||||
return -EFAULT;
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(stats_buffer);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,57 +199,88 @@ int
|
||||
acm_get_ssid(ssidref_t ssidref, u8 *buf, u16 buf_size)
|
||||
{
|
||||
/* send stats to user space */
|
||||
u8 *ssid_buffer;
|
||||
int ret;
|
||||
struct acm_ssid_buffer *acm_ssid;
|
||||
if (buf_size < sizeof(struct acm_ssid_buffer))
|
||||
return -EFAULT;
|
||||
u8 *ssid_buffer;
|
||||
int ret;
|
||||
struct acm_ssid_buffer *acm_ssid;
|
||||
if (buf_size < sizeof(struct acm_ssid_buffer))
|
||||
return -EFAULT;
|
||||
|
||||
if ((ssid_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
if ((ssid_buffer = xmalloc_array(u8, buf_size)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
|
||||
acm_ssid = (struct acm_ssid_buffer *)ssid_buffer;
|
||||
acm_ssid->len = sizeof(struct acm_ssid_buffer);
|
||||
acm_ssid->ssidref = ssidref;
|
||||
acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code;
|
||||
acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code;
|
||||
acm_ssid->primary_types_offset = acm_ssid->len;
|
||||
acm_ssid = (struct acm_ssid_buffer *)ssid_buffer;
|
||||
acm_ssid->len = sizeof(struct acm_ssid_buffer);
|
||||
acm_ssid->ssidref = ssidref;
|
||||
acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code;
|
||||
acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code;
|
||||
acm_ssid->primary_types_offset = acm_ssid->len;
|
||||
|
||||
/* ret >= 0 --> ret == max_types */
|
||||
ret = acm_primary_ops->dump_ssid_types(ACM_PRIMARY(ssidref),
|
||||
ssid_buffer + acm_ssid->primary_types_offset,
|
||||
buf_size - acm_ssid->primary_types_offset);
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
/* ret >= 0 --> ret == max_types */
|
||||
ret = acm_primary_ops->dump_ssid_types(ACM_PRIMARY(ssidref),
|
||||
ssid_buffer + acm_ssid->primary_types_offset,
|
||||
buf_size - acm_ssid->primary_types_offset);
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
|
||||
acm_ssid->len += ret;
|
||||
acm_ssid->primary_max_types = ret;
|
||||
acm_ssid->len += ret;
|
||||
acm_ssid->primary_max_types = ret;
|
||||
acm_ssid->secondary_types_offset = acm_ssid->len;
|
||||
|
||||
acm_ssid->secondary_types_offset = acm_ssid->len;
|
||||
ret = acm_secondary_ops->dump_ssid_types(ACM_SECONDARY(ssidref),
|
||||
ssid_buffer + acm_ssid->secondary_types_offset,
|
||||
buf_size - acm_ssid->secondary_types_offset);
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
|
||||
ret = acm_secondary_ops->dump_ssid_types(ACM_SECONDARY(ssidref),
|
||||
ssid_buffer + acm_ssid->secondary_types_offset,
|
||||
buf_size - acm_ssid->secondary_types_offset);
|
||||
if (ret < 0)
|
||||
goto error_free_unlock;
|
||||
acm_ssid->len += ret;
|
||||
acm_ssid->secondary_max_types = ret;
|
||||
|
||||
acm_ssid->len += ret;
|
||||
acm_ssid->secondary_max_types = ret;
|
||||
if (copy_to_user(buf, ssid_buffer, acm_ssid->len))
|
||||
goto error_free_unlock;
|
||||
|
||||
if (copy_to_user(buf, ssid_buffer, acm_ssid->len))
|
||||
goto error_free_unlock;
|
||||
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(ssid_buffer);
|
||||
return ACM_OK;
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
xfree(ssid_buffer);
|
||||
return ACM_OK;
|
||||
|
||||
error_free_unlock:
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
printk("%s: Error getting ssid.\n", __func__);
|
||||
xfree(ssid_buffer);
|
||||
return -ENOMEM;
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
printk("%s: Error getting ssid.\n", __func__);
|
||||
xfree(ssid_buffer);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*eof*/
|
||||
int
|
||||
acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2,
|
||||
enum acm_hook_type hook)
|
||||
{
|
||||
int ret = ACM_ACCESS_DENIED;
|
||||
switch (hook) {
|
||||
|
||||
case SHARING:
|
||||
/* SHARING Hook restricts access in STE policy only */
|
||||
ret = acm_sharing(ssidref1, ssidref2);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* deny */
|
||||
break;
|
||||
}
|
||||
|
||||
printkd("%s: ssid1=%x, ssid2=%x, decision=%s.\n",
|
||||
__func__, ssidref1, ssidref2,
|
||||
(ret == ACM_ACCESS_PERMITTED) ? "GRANTED" : "DENIED");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -24,6 +24,7 @@
|
||||
* share at least on common type.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xen/lib.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/current.h>
|
||||
@@ -35,34 +36,34 @@
|
||||
struct ste_binary_policy ste_bin_pol;
|
||||
|
||||
static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
|
||||
int i;
|
||||
for(i=0; i< ste_bin_pol.max_types; i++)
|
||||
if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
|
||||
ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) {
|
||||
printkd("%s: common type #%02x.\n", __func__, i);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
int i;
|
||||
for(i=0; i< ste_bin_pol.max_types; i++)
|
||||
if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
|
||||
ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) {
|
||||
printkd("%s: common type #%02x.\n", __func__, i);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function: return = (subj and obj share a common type) */
|
||||
static int share_common_type(struct domain *subj, struct domain *obj)
|
||||
{
|
||||
ssidref_t ref_s, ref_o;
|
||||
int ret;
|
||||
ssidref_t ref_s, ref_o;
|
||||
int ret;
|
||||
|
||||
if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL))
|
||||
return 0;
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
/* lookup the policy-local ssids */
|
||||
ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;
|
||||
ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;
|
||||
/* check whether subj and obj share a common ste type */
|
||||
ret = have_common_type(ref_s, ref_o);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ret;
|
||||
if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL))
|
||||
return 0;
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
/* lookup the policy-local ssids */
|
||||
ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;
|
||||
ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;
|
||||
/* check whether subj and obj share a common ste type */
|
||||
ret = have_common_type(ref_s, ref_o);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -71,26 +72,26 @@ static int share_common_type(struct domain *subj, struct domain *obj)
|
||||
*/
|
||||
int acm_init_ste_policy(void)
|
||||
{
|
||||
/* minimal startup policy; policy write-locked already */
|
||||
ste_bin_pol.max_types = 1;
|
||||
ste_bin_pol.max_ssidrefs = 2;
|
||||
ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 2);
|
||||
memset(ste_bin_pol.ssidrefs, 0, 2);
|
||||
/* minimal startup policy; policy write-locked already */
|
||||
ste_bin_pol.max_types = 1;
|
||||
ste_bin_pol.max_ssidrefs = 2;
|
||||
ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 2);
|
||||
memset(ste_bin_pol.ssidrefs, 0, 2);
|
||||
|
||||
if (ste_bin_pol.ssidrefs == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
if (ste_bin_pol.ssidrefs == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
|
||||
/* initialize state so that dom0 can start up and communicate with itself */
|
||||
ste_bin_pol.ssidrefs[1] = 1;
|
||||
/* initialize state so that dom0 can start up and communicate with itself */
|
||||
ste_bin_pol.ssidrefs[1] = 1;
|
||||
|
||||
/* init stats */
|
||||
atomic_set(&(ste_bin_pol.ec_eval_count), 0);
|
||||
atomic_set(&(ste_bin_pol.ec_denied_count), 0);
|
||||
atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);
|
||||
atomic_set(&(ste_bin_pol.gt_eval_count), 0);
|
||||
atomic_set(&(ste_bin_pol.gt_denied_count), 0);
|
||||
atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);
|
||||
return ACM_OK;
|
||||
/* init stats */
|
||||
atomic_set(&(ste_bin_pol.ec_eval_count), 0);
|
||||
atomic_set(&(ste_bin_pol.ec_denied_count), 0);
|
||||
atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);
|
||||
atomic_set(&(ste_bin_pol.gt_eval_count), 0);
|
||||
atomic_set(&(ste_bin_pol.gt_denied_count), 0);
|
||||
atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,62 +99,68 @@ int acm_init_ste_policy(void)
|
||||
static int
|
||||
ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref)
|
||||
{
|
||||
int i;
|
||||
struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid);
|
||||
traceprintk("%s.\n", __func__);
|
||||
int i;
|
||||
struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid);
|
||||
traceprintk("%s.\n", __func__);
|
||||
|
||||
if (ste_ssidp == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
if (ste_ssidp == NULL)
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
|
||||
/* get policy-local ssid reference */
|
||||
ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
|
||||
if ((ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) ||
|
||||
(ste_ssidp->ste_ssidref == ACM_DEFAULT_LOCAL_SSID)) {
|
||||
printkd("%s: ERROR ste_ssidref (%x) undefined or unset (0).\n",
|
||||
__func__, ste_ssidp->ste_ssidref);
|
||||
xfree(ste_ssidp);
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
}
|
||||
/* clean ste cache */
|
||||
for (i=0; i<ACM_TE_CACHE_SIZE; i++)
|
||||
ste_ssidp->ste_cache[i].valid = FREE;
|
||||
/* get policy-local ssid reference */
|
||||
ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
|
||||
if ((ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) ||
|
||||
(ste_ssidp->ste_ssidref == ACM_DEFAULT_LOCAL_SSID)) {
|
||||
printkd("%s: ERROR ste_ssidref (%x) undefined or unset (0).\n",
|
||||
__func__, ste_ssidp->ste_ssidref);
|
||||
xfree(ste_ssidp);
|
||||
return ACM_INIT_SSID_ERROR;
|
||||
}
|
||||
/* clean ste cache */
|
||||
for (i=0; i<ACM_TE_CACHE_SIZE; i++)
|
||||
ste_ssidp->ste_cache[i].valid = FREE;
|
||||
|
||||
(*ste_ssid) = ste_ssidp;
|
||||
printkd("%s: determined ste_ssidref to %x.\n",
|
||||
__func__, ste_ssidp->ste_ssidref);
|
||||
return ACM_OK;
|
||||
(*ste_ssid) = ste_ssidp;
|
||||
printkd("%s: determined ste_ssidref to %x.\n",
|
||||
__func__, ste_ssidp->ste_ssidref);
|
||||
return ACM_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ste_free_domain_ssid(void *ste_ssid)
|
||||
{
|
||||
traceprintk("%s.\n", __func__);
|
||||
if (ste_ssid != NULL)
|
||||
xfree(ste_ssid);
|
||||
return;
|
||||
traceprintk("%s.\n", __func__);
|
||||
if (ste_ssid != NULL)
|
||||
xfree(ste_ssid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* dump type enforcement cache; policy read-locked already */
|
||||
static int
|
||||
ste_dump_policy(u8 *buf, u16 buf_size) {
|
||||
struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
|
||||
int ret = 0;
|
||||
ste_dump_policy(u8 *buf, u32 buf_size) {
|
||||
struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
|
||||
int ret = 0;
|
||||
|
||||
ste_buf->ste_max_types = htonl(ste_bin_pol.max_types);
|
||||
ste_buf->ste_max_ssidrefs = htonl(ste_bin_pol.max_ssidrefs);
|
||||
ste_buf->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
|
||||
ste_buf->ste_ssid_offset = htonl(sizeof(struct acm_ste_policy_buffer));
|
||||
ret = ntohl(ste_buf->ste_ssid_offset) +
|
||||
sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
|
||||
if (buf_size < sizeof(struct acm_ste_policy_buffer))
|
||||
return -EINVAL;
|
||||
|
||||
/* now copy buffer over */
|
||||
arrcpy(buf + ntohl(ste_buf->ste_ssid_offset),
|
||||
ste_bin_pol.ssidrefs,
|
||||
sizeof(domaintype_t),
|
||||
ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
|
||||
ste_buf->ste_max_types = htonl(ste_bin_pol.max_types);
|
||||
ste_buf->ste_max_ssidrefs = htonl(ste_bin_pol.max_ssidrefs);
|
||||
ste_buf->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
|
||||
ste_buf->ste_ssid_offset = htonl(sizeof(struct acm_ste_policy_buffer));
|
||||
ret = ntohl(ste_buf->ste_ssid_offset) +
|
||||
sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
|
||||
|
||||
return ret;
|
||||
if (buf_size < ret)
|
||||
return -EINVAL;
|
||||
|
||||
/* now copy buffer over */
|
||||
arrcpy(buf + ntohl(ste_buf->ste_ssid_offset),
|
||||
ste_bin_pol.ssidrefs,
|
||||
sizeof(domaintype_t),
|
||||
ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ste_init_state is called when a policy is changed to detect violations (return != 0).
|
||||
@@ -176,83 +183,83 @@ ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
|
||||
/* go through all domains and adjust policy as if this domain was started now */
|
||||
pd = &domain_list;
|
||||
for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(*pd)->ssid);
|
||||
ste_ssidref = ste_ssid->ste_ssidref;
|
||||
traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
|
||||
__func__, (*pd)->domain_id, ste_ssidref);
|
||||
/* a) check for event channel conflicts */
|
||||
for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
|
||||
spin_lock(&(*pd)->evtchn_lock);
|
||||
if ((*pd)->evtchn[port] == NULL) {
|
||||
spin_unlock(&(*pd)->evtchn_lock);
|
||||
continue;
|
||||
}
|
||||
if ((*pd)->evtchn[port]->state == ECS_INTERDOMAIN) {
|
||||
rdom = (*pd)->evtchn[port]->u.interdomain.remote_dom;
|
||||
rdomid = rdom->domain_id;
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
} else if ((*pd)->evtchn[port]->state == ECS_UNBOUND) {
|
||||
rdomid = (*pd)->evtchn[port]->u.unbound.remote_domid;
|
||||
if ((rdom = find_domain_by_id(rdomid)) == NULL) {
|
||||
printk("%s: Error finding domain to id %x!\n", __func__, rdomid);
|
||||
goto out;
|
||||
}
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
put_domain(rdom);
|
||||
} else {
|
||||
spin_unlock(&(*pd)->evtchn_lock);
|
||||
continue; /* port unused */
|
||||
}
|
||||
spin_unlock(&(*pd)->evtchn_lock);
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(*pd)->ssid);
|
||||
ste_ssidref = ste_ssid->ste_ssidref;
|
||||
traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
|
||||
__func__, (*pd)->domain_id, ste_ssidref);
|
||||
/* a) check for event channel conflicts */
|
||||
for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
|
||||
spin_lock(&(*pd)->evtchn_lock);
|
||||
if ((*pd)->evtchn[port] == NULL) {
|
||||
spin_unlock(&(*pd)->evtchn_lock);
|
||||
continue;
|
||||
}
|
||||
if ((*pd)->evtchn[port]->state == ECS_INTERDOMAIN) {
|
||||
rdom = (*pd)->evtchn[port]->u.interdomain.remote_dom;
|
||||
rdomid = rdom->domain_id;
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
} else if ((*pd)->evtchn[port]->state == ECS_UNBOUND) {
|
||||
rdomid = (*pd)->evtchn[port]->u.unbound.remote_domid;
|
||||
if ((rdom = find_domain_by_id(rdomid)) == NULL) {
|
||||
printk("%s: Error finding domain to id %x!\n", __func__, rdomid);
|
||||
goto out;
|
||||
}
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
put_domain(rdom);
|
||||
} else {
|
||||
spin_unlock(&(*pd)->evtchn_lock);
|
||||
continue; /* port unused */
|
||||
}
|
||||
spin_unlock(&(*pd)->evtchn_lock);
|
||||
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x (rssidref %x) used (port %x).\n",
|
||||
__func__, (*pd)->domain_id, ste_ssidref, rdom->domain_id, ste_rssidref, port);
|
||||
/* check whether on subj->ssid, obj->ssid share a common type*/
|
||||
if (!have_common_type(ste_ssidref, ste_rssidref)) {
|
||||
printkd("%s: Policy violation in event channel domain %x -> domain %x.\n",
|
||||
__func__, (*pd)->domain_id, rdomid);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* b) check for grant table conflicts on shared pages */
|
||||
if ((*pd)->grant_table->shared == NULL) {
|
||||
printkd("%s: Grant ... sharing for domain %x not setup!\n", __func__, (*pd)->domain_id);
|
||||
continue;
|
||||
}
|
||||
for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) {
|
||||
sha_copy = (*pd)->grant_table->shared[i];
|
||||
if ( sha_copy.flags ) {
|
||||
printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%lx)\n",
|
||||
__func__, (*pd)->domain_id, i, sha_copy.flags, sha_copy.domid,
|
||||
(unsigned long)sha_copy.frame);
|
||||
rdomid = sha_copy.domid;
|
||||
if ((rdom = find_domain_by_id(rdomid)) == NULL) {
|
||||
printkd("%s: domain not found ERROR!\n", __func__);
|
||||
goto out;
|
||||
};
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
put_domain(rdom);
|
||||
if (!have_common_type(ste_ssidref, ste_rssidref)) {
|
||||
printkd("%s: Policy violation in grant table sharing domain %x -> domain %x.\n",
|
||||
__func__, (*pd)->domain_id, rdomid);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x (rssidref %x) used (port %x).\n",
|
||||
__func__, (*pd)->domain_id, ste_ssidref, rdom->domain_id, ste_rssidref, port);
|
||||
/* check whether on subj->ssid, obj->ssid share a common type*/
|
||||
if (!have_common_type(ste_ssidref, ste_rssidref)) {
|
||||
printkd("%s: Policy violation in event channel domain %x -> domain %x.\n",
|
||||
__func__, (*pd)->domain_id, rdomid);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* b) check for grant table conflicts on shared pages */
|
||||
if ((*pd)->grant_table->shared == NULL) {
|
||||
printkd("%s: Grant ... sharing for domain %x not setup!\n", __func__, (*pd)->domain_id);
|
||||
continue;
|
||||
}
|
||||
for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) {
|
||||
sha_copy = (*pd)->grant_table->shared[i];
|
||||
if ( sha_copy.flags ) {
|
||||
printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%lx)\n",
|
||||
__func__, (*pd)->domain_id, i, sha_copy.flags, sha_copy.domid,
|
||||
(unsigned long)sha_copy.frame);
|
||||
rdomid = sha_copy.domid;
|
||||
if ((rdom = find_domain_by_id(rdomid)) == NULL) {
|
||||
printkd("%s: domain not found ERROR!\n", __func__);
|
||||
goto out;
|
||||
};
|
||||
/* rdom now has remote domain */
|
||||
ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(rdom->ssid));
|
||||
ste_rssidref = ste_rssid->ste_ssidref;
|
||||
put_domain(rdom);
|
||||
if (!have_common_type(ste_ssidref, ste_rssidref)) {
|
||||
printkd("%s: Policy violation in grant table sharing domain %x -> domain %x.\n",
|
||||
__func__, (*pd)->domain_id, rdomid);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
violation = 0;
|
||||
out:
|
||||
@@ -267,69 +274,72 @@ ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
|
||||
|
||||
/* set new policy; policy write-locked already */
|
||||
static int
|
||||
ste_set_policy(u8 *buf, u16 buf_size)
|
||||
ste_set_policy(u8 *buf, u32 buf_size)
|
||||
{
|
||||
struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
|
||||
void *ssidrefsbuf;
|
||||
struct ste_ssid *ste_ssid;
|
||||
struct domain **pd;
|
||||
int i;
|
||||
struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
|
||||
void *ssidrefsbuf;
|
||||
struct ste_ssid *ste_ssid;
|
||||
struct domain **pd;
|
||||
int i;
|
||||
|
||||
/* Convert endianess of policy */
|
||||
ste_buf->policy_code = ntohl(ste_buf->policy_code);
|
||||
ste_buf->policy_version = ntohl(ste_buf->policy_version);
|
||||
ste_buf->ste_max_types = ntohl(ste_buf->ste_max_types);
|
||||
ste_buf->ste_max_ssidrefs = ntohl(ste_buf->ste_max_ssidrefs);
|
||||
ste_buf->ste_ssid_offset = ntohl(ste_buf->ste_ssid_offset);
|
||||
if (buf_size < sizeof(struct acm_ste_policy_buffer))
|
||||
return -EINVAL;
|
||||
|
||||
/* policy type and version checks */
|
||||
if ((ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ||
|
||||
(ste_buf->policy_version != ACM_STE_VERSION))
|
||||
return -EINVAL;
|
||||
/* Convert endianess of policy */
|
||||
ste_buf->policy_code = ntohl(ste_buf->policy_code);
|
||||
ste_buf->policy_version = ntohl(ste_buf->policy_version);
|
||||
ste_buf->ste_max_types = ntohl(ste_buf->ste_max_types);
|
||||
ste_buf->ste_max_ssidrefs = ntohl(ste_buf->ste_max_ssidrefs);
|
||||
ste_buf->ste_ssid_offset = ntohl(ste_buf->ste_ssid_offset);
|
||||
|
||||
/* 1. create and copy-in new ssidrefs buffer */
|
||||
ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
|
||||
if (ssidrefsbuf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
|
||||
goto error_free;
|
||||
/* policy type and version checks */
|
||||
if ((ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ||
|
||||
(ste_buf->policy_version != ACM_STE_VERSION))
|
||||
return -EINVAL;
|
||||
|
||||
arrcpy(ssidrefsbuf,
|
||||
buf + ste_buf->ste_ssid_offset,
|
||||
sizeof(domaintype_t),
|
||||
ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
|
||||
/* 1. create and copy-in new ssidrefs buffer */
|
||||
ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
|
||||
if (ssidrefsbuf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
|
||||
goto error_free;
|
||||
|
||||
/* 2. now re-calculate sharing decisions based on running domains;
|
||||
* this can fail if new policy is conflicting with sharing of running domains
|
||||
* now: reject violating new policy; future: adjust sharing through revoking sharing */
|
||||
if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
|
||||
printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
|
||||
goto error_free; /* new policy conflicts with sharing of running domains */
|
||||
}
|
||||
/* 3. replace old policy (activate new policy) */
|
||||
ste_bin_pol.max_types = ste_buf->ste_max_types;
|
||||
ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
|
||||
if (ste_bin_pol.ssidrefs)
|
||||
xfree(ste_bin_pol.ssidrefs);
|
||||
ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
|
||||
arrcpy(ssidrefsbuf,
|
||||
buf + ste_buf->ste_ssid_offset,
|
||||
sizeof(domaintype_t),
|
||||
ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
|
||||
|
||||
/* clear all ste caches */
|
||||
read_lock(&domlist_lock);
|
||||
pd = &domain_list;
|
||||
for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(*pd)->ssid);
|
||||
for (i=0; i<ACM_TE_CACHE_SIZE; i++)
|
||||
ste_ssid->ste_cache[i].valid = FREE;
|
||||
}
|
||||
read_unlock(&domlist_lock);
|
||||
return ACM_OK;
|
||||
/* 2. now re-calculate sharing decisions based on running domains;
|
||||
* this can fail if new policy is conflicting with sharing of running domains
|
||||
* now: reject violating new policy; future: adjust sharing through revoking sharing */
|
||||
if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
|
||||
printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
|
||||
goto error_free; /* new policy conflicts with sharing of running domains */
|
||||
}
|
||||
/* 3. replace old policy (activate new policy) */
|
||||
ste_bin_pol.max_types = ste_buf->ste_max_types;
|
||||
ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
|
||||
if (ste_bin_pol.ssidrefs)
|
||||
xfree(ste_bin_pol.ssidrefs);
|
||||
ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
|
||||
|
||||
error_free:
|
||||
printk("%s: ERROR setting policy.\n", __func__);
|
||||
if (ssidrefsbuf != NULL) xfree(ssidrefsbuf);
|
||||
return -EFAULT;
|
||||
/* clear all ste caches */
|
||||
read_lock(&domlist_lock);
|
||||
pd = &domain_list;
|
||||
for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(*pd)->ssid);
|
||||
for (i=0; i<ACM_TE_CACHE_SIZE; i++)
|
||||
ste_ssid->ste_cache[i].valid = FREE;
|
||||
}
|
||||
read_unlock(&domlist_lock);
|
||||
return ACM_OK;
|
||||
|
||||
error_free:
|
||||
printk("%s: ERROR setting policy.\n", __func__);
|
||||
if (ssidrefsbuf != NULL) xfree(ssidrefsbuf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -337,41 +347,6 @@ ste_dump_stats(u8 *buf, u16 buf_len)
|
||||
{
|
||||
struct acm_ste_stats_buffer stats;
|
||||
|
||||
#ifdef ACM_DEBUG
|
||||
int i;
|
||||
struct ste_ssid *ste_ssid;
|
||||
struct domain **pd;
|
||||
|
||||
printk("ste: Decision caches:\n");
|
||||
/* go through all domains and adjust policy as if this domain was started now */
|
||||
read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
|
||||
pd = &domain_list;
|
||||
for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
|
||||
printk("ste: Cache Domain %02x.\n", (*pd)->domain_id);
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(*pd)->ssid);
|
||||
for (i=0; i<ACM_TE_CACHE_SIZE; i++)
|
||||
printk("\t\tcache[%02x] = %s, domid=%x.\n", i,
|
||||
(ste_ssid->ste_cache[i].valid == VALID) ?
|
||||
"VALID" : "FREE",
|
||||
(ste_ssid->ste_cache[i].valid == VALID) ?
|
||||
ste_ssid->ste_cache[i].id : 0xffffffff);
|
||||
}
|
||||
read_unlock(&domlist_lock);
|
||||
/* init stats */
|
||||
printk("STE-Policy Security Hook Statistics:\n");
|
||||
printk("ste: event_channel eval_count = %x\n", atomic_read(&(ste_bin_pol.ec_eval_count)));
|
||||
printk("ste: event_channel denied_count = %x\n", atomic_read(&(ste_bin_pol.ec_denied_count)));
|
||||
printk("ste: event_channel cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.ec_cachehit_count)));
|
||||
printk("ste:\n");
|
||||
printk("ste: grant_table eval_count = %x\n", atomic_read(&(ste_bin_pol.gt_eval_count)));
|
||||
printk("ste: grant_table denied_count = %x\n", atomic_read(&(ste_bin_pol.gt_denied_count)));
|
||||
printk("ste: grant_table cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.gt_cachehit_count)));
|
||||
#endif
|
||||
|
||||
if (buf_len < sizeof(struct acm_ste_stats_buffer))
|
||||
return -ENOMEM;
|
||||
|
||||
/* now send the hook counts to user space */
|
||||
stats.ec_eval_count = htonl(atomic_read(&ste_bin_pol.ec_eval_count));
|
||||
stats.gt_eval_count = htonl(atomic_read(&ste_bin_pol.gt_eval_count));
|
||||
@@ -379,6 +354,10 @@ ste_dump_stats(u8 *buf, u16 buf_len)
|
||||
stats.gt_denied_count = htonl(atomic_read(&ste_bin_pol.gt_denied_count));
|
||||
stats.ec_cachehit_count = htonl(atomic_read(&ste_bin_pol.ec_cachehit_count));
|
||||
stats.gt_cachehit_count = htonl(atomic_read(&ste_bin_pol.gt_cachehit_count));
|
||||
|
||||
if (buf_len < sizeof(struct acm_ste_stats_buffer))
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
|
||||
return sizeof(struct acm_ste_stats_buffer);
|
||||
}
|
||||
@@ -392,12 +371,12 @@ ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
|
||||
if (ste_bin_pol.max_types > len)
|
||||
return -EFAULT;
|
||||
|
||||
if (ssidref >= ste_bin_pol.max_ssidrefs)
|
||||
return -EFAULT;
|
||||
if (ssidref >= ste_bin_pol.max_ssidrefs)
|
||||
return -EFAULT;
|
||||
|
||||
/* read types for chwall ssidref */
|
||||
for(i=0; i< ste_bin_pol.max_types; i++) {
|
||||
if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i])
|
||||
if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i])
|
||||
buf[i] = 1;
|
||||
else
|
||||
buf[i] = 0;
|
||||
@@ -409,40 +388,40 @@ ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
|
||||
* returns 1 == cache hit */
|
||||
static int inline
|
||||
check_cache(struct domain *dom, domid_t rdom) {
|
||||
struct ste_ssid *ste_ssid;
|
||||
int i;
|
||||
struct ste_ssid *ste_ssid;
|
||||
int i;
|
||||
|
||||
printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(dom)->ssid);
|
||||
printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(dom)->ssid);
|
||||
|
||||
for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
|
||||
if ((ste_ssid->ste_cache[i].valid == VALID) &&
|
||||
(ste_ssid->ste_cache[i].id == rdom)) {
|
||||
printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
|
||||
if ((ste_ssid->ste_cache[i].valid == VALID) &&
|
||||
(ste_ssid->ste_cache[i].id == rdom)) {
|
||||
printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* we only get here if there is NO entry yet; no duplication check! */
|
||||
static void inline
|
||||
cache_result(struct domain *subj, struct domain *obj) {
|
||||
struct ste_ssid *ste_ssid;
|
||||
int i;
|
||||
printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(subj)->ssid);
|
||||
for(i=0; i< ACM_TE_CACHE_SIZE; i++)
|
||||
if (ste_ssid->ste_cache[i].valid == FREE)
|
||||
break;
|
||||
if (i< ACM_TE_CACHE_SIZE) {
|
||||
ste_ssid->ste_cache[i].valid = VALID;
|
||||
ste_ssid->ste_cache[i].id = obj->domain_id;
|
||||
} else
|
||||
printk ("Cache of dom %x is full!\n", subj->domain_id);
|
||||
struct ste_ssid *ste_ssid;
|
||||
int i;
|
||||
printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(subj)->ssid);
|
||||
for(i=0; i< ACM_TE_CACHE_SIZE; i++)
|
||||
if (ste_ssid->ste_cache[i].valid == FREE)
|
||||
break;
|
||||
if (i< ACM_TE_CACHE_SIZE) {
|
||||
ste_ssid->ste_cache[i].valid = VALID;
|
||||
ste_ssid->ste_cache[i].id = obj->domain_id;
|
||||
} else
|
||||
printk ("Cache of dom %x is full!\n", subj->domain_id);
|
||||
}
|
||||
|
||||
/* deletes entries for domain 'id' from all caches (re-use) */
|
||||
@@ -458,12 +437,12 @@ clean_id_from_cache(domid_t id)
|
||||
read_lock(&domlist_lock); /* look through caches of all domains */
|
||||
pd = &domain_list;
|
||||
for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(*pd)->ssid);
|
||||
for (i=0; i<ACM_TE_CACHE_SIZE; i++)
|
||||
if ((ste_ssid->ste_cache[i].valid == VALID) &&
|
||||
(ste_ssid->ste_cache[i].id = id))
|
||||
ste_ssid->ste_cache[i].valid = FREE;
|
||||
ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
|
||||
(struct acm_ssid_domain *)(*pd)->ssid);
|
||||
for (i=0; i<ACM_TE_CACHE_SIZE; i++)
|
||||
if ((ste_ssid->ste_cache[i].valid == VALID) &&
|
||||
(ste_ssid->ste_cache[i].id = id))
|
||||
ste_ssid->ste_cache[i].valid = FREE;
|
||||
}
|
||||
read_unlock(&domlist_lock);
|
||||
}
|
||||
@@ -482,15 +461,15 @@ ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
|
||||
read_lock(&acm_bin_pol_rwlock);
|
||||
ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
|
||||
if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) {
|
||||
printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED; /* catching and indicating config error */
|
||||
printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED; /* catching and indicating config error */
|
||||
}
|
||||
if (ste_ssidref >= ste_bin_pol.max_ssidrefs) {
|
||||
printk("%s: ERROR ste_ssidref > max(%x).\n",
|
||||
__func__, ste_bin_pol.max_ssidrefs-1);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED;
|
||||
printk("%s: ERROR ste_ssidref > max(%x).\n",
|
||||
__func__, ste_bin_pol.max_ssidrefs-1);
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
read_unlock(&acm_bin_pol_rwlock);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
@@ -506,163 +485,193 @@ ste_post_domain_destroy(void *subject_ssid, domid_t id)
|
||||
/* -------- EVENTCHANNEL OPERATIONS -----------*/
|
||||
static int
|
||||
ste_pre_eventchannel_unbound(domid_t id) {
|
||||
struct domain *subj, *obj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n",
|
||||
__func__, current->domain->domain_id, id);
|
||||
struct domain *subj, *obj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n",
|
||||
__func__, current->domain->domain_id, id);
|
||||
|
||||
if (check_cache(current->domain, id)) {
|
||||
atomic_inc(&ste_bin_pol.ec_cachehit_count);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.ec_eval_count);
|
||||
subj = current->domain;
|
||||
obj = find_domain_by_id(id);
|
||||
if (check_cache(current->domain, id)) {
|
||||
atomic_inc(&ste_bin_pol.ec_cachehit_count);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.ec_eval_count);
|
||||
subj = current->domain;
|
||||
obj = find_domain_by_id(id);
|
||||
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.ec_denied_count);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
return ret;
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.ec_denied_count);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
ste_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
|
||||
{
|
||||
struct domain *subj, *obj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n", __func__,
|
||||
(id1 == DOMID_SELF) ? current->domain->domain_id : id1,
|
||||
(id2 == DOMID_SELF) ? current->domain->domain_id : id2);
|
||||
struct domain *subj, *obj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n", __func__,
|
||||
(id1 == DOMID_SELF) ? current->domain->domain_id : id1,
|
||||
(id2 == DOMID_SELF) ? current->domain->domain_id : id2);
|
||||
|
||||
/* following is a bit longer but ensures that we
|
||||
* "put" only domains that we where "find"-ing
|
||||
*/
|
||||
if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
|
||||
if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
|
||||
/* following is a bit longer but ensures that we
|
||||
* "put" only domains that we where "find"-ing
|
||||
*/
|
||||
if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
|
||||
if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
|
||||
|
||||
subj = find_domain_by_id(id1);
|
||||
obj = find_domain_by_id(id2);
|
||||
if ((subj == NULL) || (obj == NULL)) {
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
goto out;
|
||||
}
|
||||
/* cache check late, but evtchn is not on performance critical path */
|
||||
if (check_cache(subj, obj->domain_id)) {
|
||||
atomic_inc(&ste_bin_pol.ec_cachehit_count);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
goto out;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.ec_eval_count);
|
||||
subj = find_domain_by_id(id1);
|
||||
obj = find_domain_by_id(id2);
|
||||
if ((subj == NULL) || (obj == NULL)) {
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
goto out;
|
||||
}
|
||||
/* cache check late, but evtchn is not on performance critical path */
|
||||
if (check_cache(subj, obj->domain_id)) {
|
||||
atomic_inc(&ste_bin_pol.ec_cachehit_count);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
goto out;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.ec_eval_count);
|
||||
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.ec_denied_count);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.ec_denied_count);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
out:
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
if (subj != NULL)
|
||||
put_domain(subj);
|
||||
return ret;
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
if (subj != NULL)
|
||||
put_domain(subj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------- SHARED MEMORY OPERATIONS -----------*/
|
||||
|
||||
static int
|
||||
ste_pre_grant_map_ref (domid_t id) {
|
||||
struct domain *obj, *subj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n", __func__,
|
||||
current->domain->domain_id, id);
|
||||
struct domain *obj, *subj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n", __func__,
|
||||
current->domain->domain_id, id);
|
||||
|
||||
if (check_cache(current->domain, id)) {
|
||||
atomic_inc(&ste_bin_pol.gt_cachehit_count);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.gt_eval_count);
|
||||
subj = current->domain;
|
||||
obj = find_domain_by_id(id);
|
||||
if (check_cache(current->domain, id)) {
|
||||
atomic_inc(&ste_bin_pol.gt_cachehit_count);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.gt_eval_count);
|
||||
subj = current->domain;
|
||||
obj = find_domain_by_id(id);
|
||||
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.gt_denied_count);
|
||||
printkd("%s: ACCESS DENIED!\n", __func__);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
return ret;
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.gt_denied_count);
|
||||
printkd("%s: ACCESS DENIED!\n", __func__);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* since setting up grant tables involves some implicit information
|
||||
flow from the creating domain to the domain that is setup, we
|
||||
check types in addition to the general authorization */
|
||||
static int
|
||||
ste_pre_grant_setup (domid_t id) {
|
||||
struct domain *obj, *subj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n", __func__,
|
||||
current->domain->domain_id, id);
|
||||
struct domain *obj, *subj;
|
||||
int ret;
|
||||
traceprintk("%s: dom%x-->dom%x.\n", __func__,
|
||||
current->domain->domain_id, id);
|
||||
|
||||
if (check_cache(current->domain, id)) {
|
||||
atomic_inc(&ste_bin_pol.gt_cachehit_count);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.gt_eval_count);
|
||||
/* a) check authorization (eventually use specific capabilities) */
|
||||
if (!IS_PRIV(current->domain)) {
|
||||
printk("%s: Grant table management authorization denied ERROR!\n", __func__);
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
/* b) check types */
|
||||
subj = current->domain;
|
||||
obj = find_domain_by_id(id);
|
||||
if (check_cache(current->domain, id)) {
|
||||
atomic_inc(&ste_bin_pol.gt_cachehit_count);
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
atomic_inc(&ste_bin_pol.gt_eval_count);
|
||||
/* a) check authorization (eventually use specific capabilities) */
|
||||
if (!IS_PRIV(current->domain)) {
|
||||
printk("%s: Grant table management authorization denied ERROR!\n", __func__);
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
/* b) check types */
|
||||
subj = current->domain;
|
||||
obj = find_domain_by_id(id);
|
||||
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.gt_denied_count);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
return ret;
|
||||
if (share_common_type(subj, obj)) {
|
||||
cache_result(subj, obj);
|
||||
ret = ACM_ACCESS_PERMITTED;
|
||||
} else {
|
||||
atomic_inc(&ste_bin_pol.gt_denied_count);
|
||||
ret = ACM_ACCESS_DENIED;
|
||||
}
|
||||
if (obj != NULL)
|
||||
put_domain(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------- DOMAIN-Requested Decision hooks -----------*/
|
||||
|
||||
static int
|
||||
ste_sharing(ssidref_t ssidref1, ssidref_t ssidref2) {
|
||||
if (have_common_type (
|
||||
GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
|
||||
GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2)
|
||||
))
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
else
|
||||
return ACM_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
|
||||
/* now define the hook structure similarly to LSM */
|
||||
struct acm_operations acm_simple_type_enforcement_ops = {
|
||||
/* policy management services */
|
||||
.init_domain_ssid = ste_init_domain_ssid,
|
||||
.free_domain_ssid = ste_free_domain_ssid,
|
||||
.dump_binary_policy = ste_dump_policy,
|
||||
.set_binary_policy = ste_set_policy,
|
||||
.dump_statistics = ste_dump_stats,
|
||||
|
||||
/* policy management services */
|
||||
.init_domain_ssid = ste_init_domain_ssid,
|
||||
.free_domain_ssid = ste_free_domain_ssid,
|
||||
.dump_binary_policy = ste_dump_policy,
|
||||
.set_binary_policy = ste_set_policy,
|
||||
.dump_statistics = ste_dump_stats,
|
||||
.dump_ssid_types = ste_dump_ssid_types,
|
||||
/* domain management control hooks */
|
||||
.pre_domain_create = ste_pre_domain_create,
|
||||
.post_domain_create = NULL,
|
||||
.fail_domain_create = NULL,
|
||||
.post_domain_destroy = ste_post_domain_destroy,
|
||||
/* event channel control hooks */
|
||||
.pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
|
||||
.fail_eventchannel_unbound = NULL,
|
||||
.pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain,
|
||||
.fail_eventchannel_interdomain = NULL,
|
||||
/* grant table control hooks */
|
||||
.pre_grant_map_ref = ste_pre_grant_map_ref,
|
||||
.fail_grant_map_ref = NULL,
|
||||
.pre_grant_setup = ste_pre_grant_setup,
|
||||
.fail_grant_setup = NULL,
|
||||
|
||||
/* domain management control hooks */
|
||||
.pre_domain_create = ste_pre_domain_create,
|
||||
.post_domain_create = NULL,
|
||||
.fail_domain_create = NULL,
|
||||
.post_domain_destroy = ste_post_domain_destroy,
|
||||
|
||||
/* event channel control hooks */
|
||||
.pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
|
||||
.fail_eventchannel_unbound = NULL,
|
||||
.pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain,
|
||||
.fail_eventchannel_interdomain = NULL,
|
||||
|
||||
/* grant table control hooks */
|
||||
.pre_grant_map_ref = ste_pre_grant_map_ref,
|
||||
.fail_grant_map_ref = NULL,
|
||||
.pre_grant_setup = ste_pre_grant_setup,
|
||||
.fail_grant_setup = NULL,
|
||||
.sharing = ste_sharing,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
+134
-66
@@ -31,22 +31,23 @@
|
||||
|
||||
#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
|
||||
|
||||
long do_acm_op(acm_op_t * u_acm_op)
|
||||
long do_acm_op(struct acm_op * u_acm_op)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef enum acm_operation {
|
||||
enum acm_operation {
|
||||
POLICY, /* access to policy interface (early drop) */
|
||||
GETPOLICY, /* dump policy cache */
|
||||
SETPOLICY, /* set policy cache (controls security) */
|
||||
DUMPSTATS, /* dump policy statistics */
|
||||
GETSSID /* retrieve ssidref for domain id */
|
||||
} acm_operation_t;
|
||||
GETSSID, /* retrieve ssidref for domain id (decide inside authorized domains) */
|
||||
GETDECISION /* retrieve ACM decision from authorized domains */
|
||||
};
|
||||
|
||||
int acm_authorize_acm_ops(struct domain *d, acm_operation_t pops)
|
||||
int acm_authorize_acm_ops(struct domain *d, enum acm_operation pops)
|
||||
{
|
||||
/* all policy management functions are restricted to privileged domains,
|
||||
* soon we will introduce finer-grained privileges for policy operations
|
||||
@@ -59,10 +60,10 @@ int acm_authorize_acm_ops(struct domain *d, acm_operation_t pops)
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
|
||||
long do_acm_op(acm_op_t * u_acm_op)
|
||||
long do_acm_op(struct acm_op * u_acm_op)
|
||||
{
|
||||
long ret = 0;
|
||||
acm_op_t curop, *op = &curop;
|
||||
struct acm_op curop, *op = &curop;
|
||||
|
||||
/* check here policy decision for policy commands */
|
||||
/* for now allow DOM0 only, later indepedently */
|
||||
@@ -78,81 +79,148 @@ long do_acm_op(acm_op_t * u_acm_op)
|
||||
switch (op->cmd)
|
||||
{
|
||||
case ACM_SETPOLICY:
|
||||
{
|
||||
if (acm_authorize_acm_ops(current->domain, SETPOLICY))
|
||||
return -EACCES;
|
||||
printkd("%s: setting policy.\n", __func__);
|
||||
ret = acm_set_policy(op->u.setpolicy.pushcache,
|
||||
op->u.setpolicy.pushcache_size, 1);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
break;
|
||||
{
|
||||
if (acm_authorize_acm_ops(current->domain, SETPOLICY))
|
||||
return -EACCES;
|
||||
printkd("%s: setting policy.\n", __func__);
|
||||
ret = acm_set_policy(op->u.setpolicy.pushcache,
|
||||
op->u.setpolicy.pushcache_size, 1);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACM_GETPOLICY:
|
||||
{
|
||||
if (acm_authorize_acm_ops(current->domain, GETPOLICY))
|
||||
return -EACCES;
|
||||
printkd("%s: getting policy.\n", __func__);
|
||||
ret = acm_get_policy(op->u.getpolicy.pullcache,
|
||||
op->u.getpolicy.pullcache_size);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
break;
|
||||
{
|
||||
if (acm_authorize_acm_ops(current->domain, GETPOLICY))
|
||||
return -EACCES;
|
||||
printkd("%s: getting policy.\n", __func__);
|
||||
ret = acm_get_policy(op->u.getpolicy.pullcache,
|
||||
op->u.getpolicy.pullcache_size);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACM_DUMPSTATS:
|
||||
{
|
||||
if (acm_authorize_acm_ops(current->domain, DUMPSTATS))
|
||||
return -EACCES;
|
||||
printkd("%s: dumping statistics.\n", __func__);
|
||||
ret = acm_dump_statistics(op->u.dumpstats.pullcache,
|
||||
op->u.dumpstats.pullcache_size);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
break;
|
||||
{
|
||||
if (acm_authorize_acm_ops(current->domain, DUMPSTATS))
|
||||
return -EACCES;
|
||||
printkd("%s: dumping statistics.\n", __func__);
|
||||
ret = acm_dump_statistics(op->u.dumpstats.pullcache,
|
||||
op->u.dumpstats.pullcache_size);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACM_GETSSID:
|
||||
{
|
||||
ssidref_t ssidref;
|
||||
{
|
||||
ssidref_t ssidref;
|
||||
|
||||
if (acm_authorize_acm_ops(current->domain, GETSSID))
|
||||
return -EACCES;
|
||||
if (acm_authorize_acm_ops(current->domain, GETSSID))
|
||||
return -EACCES;
|
||||
printkd("%s: getting SSID.\n", __func__);
|
||||
if (op->u.getssid.get_ssid_by == SSIDREF)
|
||||
ssidref = op->u.getssid.id.ssidref;
|
||||
else if (op->u.getssid.get_ssid_by == DOMAINID) {
|
||||
struct domain *subj = find_domain_by_id(op->u.getssid.id.domainid);
|
||||
if (!subj)
|
||||
return -ESRCH; /* domain not found */
|
||||
|
||||
if (op->u.getssid.get_ssid_by == SSIDREF)
|
||||
ssidref = op->u.getssid.id.ssidref;
|
||||
else if (op->u.getssid.get_ssid_by == DOMAINID) {
|
||||
struct domain *subj = find_domain_by_id(op->u.getssid.id.domainid);
|
||||
if (!subj)
|
||||
return -ESRCH; /* domain not found */
|
||||
ssidref = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
|
||||
put_domain(subj);
|
||||
} else
|
||||
return -ESRCH;
|
||||
|
||||
ssidref = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
|
||||
put_domain(subj);
|
||||
} else
|
||||
return -ESRCH;
|
||||
ret = acm_get_ssid(ssidref,
|
||||
op->u.getssid.ssidbuf,
|
||||
op->u.getssid.ssidbuf_size);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
break;
|
||||
|
||||
ret = acm_get_ssid(ssidref,
|
||||
op->u.getssid.ssidbuf,
|
||||
op->u.getssid.ssidbuf_size);
|
||||
if (ret == ACM_OK)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -ESRCH;
|
||||
case ACM_GETDECISION:
|
||||
{
|
||||
ssidref_t ssidref1, ssidref2;
|
||||
|
||||
if (acm_authorize_acm_ops(current->domain, GETDECISION)) {
|
||||
ret = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
printkd("%s: getting access control decision.\n", __func__);
|
||||
if (op->u.getdecision.get_decision_by1 == SSIDREF) {
|
||||
ssidref1 = op->u.getdecision.id1.ssidref;
|
||||
}
|
||||
else if (op->u.getdecision.get_decision_by1 == DOMAINID) {
|
||||
struct domain *subj = find_domain_by_id(op->u.getdecision.id1.domainid);
|
||||
if (!subj) {
|
||||
ret = -ESRCH; /* domain not found */
|
||||
goto out;
|
||||
}
|
||||
ssidref1 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
|
||||
put_domain(subj);
|
||||
} else {
|
||||
ret = -ESRCH;
|
||||
goto out;
|
||||
}
|
||||
if (op->u.getdecision.get_decision_by2 == SSIDREF) {
|
||||
ssidref2 = op->u.getdecision.id2.ssidref;
|
||||
}
|
||||
else if (op->u.getdecision.get_decision_by2 == DOMAINID) {
|
||||
struct domain *subj = find_domain_by_id(op->u.getdecision.id2.domainid);
|
||||
if (!subj) {
|
||||
ret = -ESRCH; /* domain not found */
|
||||
goto out;
|
||||
}
|
||||
ssidref2 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
|
||||
put_domain(subj);
|
||||
} else {
|
||||
ret = -ESRCH;
|
||||
goto out;
|
||||
}
|
||||
ret = acm_get_decision(ssidref1, ssidref2, op->u.getdecision.hook);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ESRCH;
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret == ACM_ACCESS_PERMITTED) {
|
||||
op->u.getdecision.acm_decision = ACM_ACCESS_PERMITTED;
|
||||
ret = 0;
|
||||
} else if (ret == ACM_ACCESS_DENIED) {
|
||||
op->u.getdecision.acm_decision = ACM_ACCESS_DENIED;
|
||||
ret = 0;
|
||||
} else {
|
||||
op->u.getdecision.acm_decision = ACM_ACCESS_DENIED;
|
||||
if (ret > 0)
|
||||
ret = -ret;
|
||||
}
|
||||
/* copy decision back to user space */
|
||||
copy_to_user(u_acm_op, op, sizeof(*op));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -199,7 +199,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
|
||||
/*
|
||||
* If we're on a HT system, we only use the first HT for dom0, other
|
||||
* domains will all share the second HT of each CPU. Since dom0 is on
|
||||
* CPU 0, we favour high numbered CPUs in the event of a tie.
|
||||
* CPU 0, we favour high numbered CPUs in the event of a tie.
|
||||
*/
|
||||
pro = smp_num_siblings - 1;
|
||||
for ( i = pro; i < num_online_cpus(); i += smp_num_siblings )
|
||||
|
||||
+11
-1
@@ -1150,7 +1150,7 @@ void sedf_wake(struct vcpu *d) {
|
||||
inf->block_tot++;
|
||||
#endif
|
||||
if (unlikely(now < PERIOD_BEGIN(inf))) {
|
||||
PRINT(4,"extratime unblock\n");
|
||||
PRINT(4,"extratime unblock\n");
|
||||
/* unblocking in extra-time! */
|
||||
#if (EXTRA == EXTRA_BLOCK_WEIGHT)
|
||||
if (inf->status & EXTRA_WANT_PEN_Q) {
|
||||
@@ -1459,3 +1459,13 @@ struct scheduler sched_sedf_def = {
|
||||
.wake = sedf_wake,
|
||||
.adjdom = sedf_adjdom,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
+52
-41
@@ -15,6 +15,7 @@
|
||||
* for the access control module and relevant policies
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ACM_CORE_H
|
||||
#define _ACM_CORE_H
|
||||
|
||||
@@ -25,30 +26,30 @@
|
||||
|
||||
/* Xen-internal representation of the binary policy */
|
||||
struct acm_binary_policy {
|
||||
u16 primary_policy_code;
|
||||
u16 secondary_policy_code;
|
||||
void *primary_binary_policy;
|
||||
void *secondary_binary_policy;
|
||||
|
||||
u16 primary_policy_code;
|
||||
u16 secondary_policy_code;
|
||||
void *primary_binary_policy;
|
||||
void *secondary_binary_policy;
|
||||
|
||||
};
|
||||
|
||||
struct chwall_binary_policy {
|
||||
u16 max_types;
|
||||
u16 max_ssidrefs;
|
||||
u16 max_conflictsets;
|
||||
domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
|
||||
domaintype_t *conflict_aggregate_set; /* [max_types] */
|
||||
domaintype_t *running_types; /* [max_types] */
|
||||
domaintype_t *conflict_sets; /* [max_conflictsets][max_types]*/
|
||||
u32 max_types;
|
||||
u32 max_ssidrefs;
|
||||
u32 max_conflictsets;
|
||||
domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
|
||||
domaintype_t *conflict_aggregate_set; /* [max_types] */
|
||||
domaintype_t *running_types; /* [max_types] */
|
||||
domaintype_t *conflict_sets; /* [max_conflictsets][max_types]*/
|
||||
};
|
||||
|
||||
struct ste_binary_policy {
|
||||
u16 max_types;
|
||||
u16 max_ssidrefs;
|
||||
domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
|
||||
atomic_t ec_eval_count, gt_eval_count;
|
||||
atomic_t ec_denied_count, gt_denied_count;
|
||||
atomic_t ec_cachehit_count, gt_cachehit_count;
|
||||
u32 max_types;
|
||||
u32 max_ssidrefs;
|
||||
domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
|
||||
atomic_t ec_eval_count, gt_eval_count;
|
||||
atomic_t ec_denied_count, gt_denied_count;
|
||||
atomic_t ec_cachehit_count, gt_cachehit_count;
|
||||
};
|
||||
|
||||
/* global acm policy */
|
||||
@@ -63,7 +64,7 @@ enum acm_datatype { DOMAIN };
|
||||
|
||||
/* defines number of access decisions to other domains can be cached
|
||||
* one entry per domain, TE does not distinguish evtchn or grant_table */
|
||||
#define ACM_TE_CACHE_SIZE 8
|
||||
#define ACM_TE_CACHE_SIZE 8
|
||||
enum acm_ste_flag { VALID, FREE };
|
||||
|
||||
/* cache line:
|
||||
@@ -72,57 +73,67 @@ enum acm_ste_flag { VALID, FREE };
|
||||
* on domain cache_line.id
|
||||
*/
|
||||
struct acm_ste_cache_line {
|
||||
enum acm_ste_flag valid;
|
||||
domid_t id;
|
||||
enum acm_ste_flag valid;
|
||||
domid_t id;
|
||||
};
|
||||
|
||||
/* general definition of a subject security id */
|
||||
struct acm_ssid_domain {
|
||||
enum acm_datatype datatype; /* type of subject (e.g., partition) */
|
||||
ssidref_t ssidref; /* combined security reference */
|
||||
void *primary_ssid; /* primary policy ssid part (e.g. chinese wall) */
|
||||
void *secondary_ssid; /* secondary policy ssid part (e.g. type enforcement) */
|
||||
struct domain *subject; /* backpointer to subject structure */
|
||||
domid_t domainid; /* replicate id */
|
||||
enum acm_datatype datatype; /* type of subject (e.g., partition) */
|
||||
ssidref_t ssidref; /* combined security reference */
|
||||
void *primary_ssid; /* primary policy ssid part (e.g. chinese wall) */
|
||||
void *secondary_ssid; /* secondary policy ssid part (e.g. type enforcement) */
|
||||
struct domain *subject; /* backpointer to subject structure */
|
||||
domid_t domainid; /* replicate id */
|
||||
};
|
||||
|
||||
/* chinese wall ssid type */
|
||||
struct chwall_ssid {
|
||||
ssidref_t chwall_ssidref;
|
||||
ssidref_t chwall_ssidref;
|
||||
};
|
||||
|
||||
/* simple type enforcement ssid type */
|
||||
struct ste_ssid {
|
||||
ssidref_t ste_ssidref;
|
||||
struct acm_ste_cache_line ste_cache[ACM_TE_CACHE_SIZE]; /* decision cache */
|
||||
ssidref_t ste_ssidref;
|
||||
struct acm_ste_cache_line ste_cache[ACM_TE_CACHE_SIZE]; /* decision cache */
|
||||
};
|
||||
|
||||
/* macros to access ssidref for primary / secondary policy
|
||||
* primary ssidref = lower 16 bit
|
||||
* secondary ssidref = higher 16 bit
|
||||
* primary ssidref = lower 16 bit
|
||||
* secondary ssidref = higher 16 bit
|
||||
*/
|
||||
#define ACM_PRIMARY(ssidref) \
|
||||
((ssidref) & 0xffff)
|
||||
((ssidref) & 0xffff)
|
||||
|
||||
#define ACM_SECONDARY(ssidref) \
|
||||
((ssidref) >> 16)
|
||||
((ssidref) >> 16)
|
||||
|
||||
#define GET_SSIDREF(POLICY, ssidref) \
|
||||
((POLICY) == acm_bin_pol.primary_policy_code) ? \
|
||||
ACM_PRIMARY(ssidref) : ACM_SECONDARY(ssidref)
|
||||
((POLICY) == acm_bin_pol.primary_policy_code) ? \
|
||||
ACM_PRIMARY(ssidref) : ACM_SECONDARY(ssidref)
|
||||
|
||||
/* macros to access ssid pointer for primary / secondary policy */
|
||||
#define GET_SSIDP(POLICY, ssid) \
|
||||
((POLICY) == acm_bin_pol.primary_policy_code) ? \
|
||||
((ssid)->primary_ssid) : ((ssid)->secondary_ssid)
|
||||
((POLICY) == acm_bin_pol.primary_policy_code) ? \
|
||||
((ssid)->primary_ssid) : ((ssid)->secondary_ssid)
|
||||
|
||||
/* protos */
|
||||
int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
|
||||
int acm_free_domain_ssid(struct acm_ssid_domain *ssid);
|
||||
int acm_set_policy(void *buf, u16 buf_size, int isuserbuffer);
|
||||
int acm_get_policy(void *buf, u16 buf_size);
|
||||
void acm_free_domain_ssid(struct acm_ssid_domain *ssid);
|
||||
int acm_set_policy(void *buf, u32 buf_size, int isuserbuffer);
|
||||
int acm_get_policy(void *buf, u32 buf_size);
|
||||
int acm_dump_statistics(void *buf, u16 buf_size);
|
||||
int acm_get_ssid(ssidref_t ssidref, u8 *buf, u16 buf_size);
|
||||
int acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, enum acm_hook_type hook);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -18,6 +18,7 @@
|
||||
* big-endian policy interface
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ACM_ENDIAN_H
|
||||
#define _ACM_ENDIAN_H
|
||||
|
||||
@@ -30,10 +31,10 @@ static inline u32 ntohl(u32 x)
|
||||
{
|
||||
if (little_endian)
|
||||
return
|
||||
( (((x) >> 24) & 0xff )|
|
||||
(((x) >> 8) & 0xff00 )|
|
||||
(((x) << 8) & 0xff0000 )|
|
||||
(((x) << 24) & 0xff000000) );
|
||||
( (((x) >> 24) & 0xff )|
|
||||
(((x) >> 8) & 0xff00 )|
|
||||
(((x) << 8) & 0xff0000 )|
|
||||
(((x) << 24) & 0xff000000) );
|
||||
else
|
||||
return x;
|
||||
}
|
||||
@@ -42,10 +43,10 @@ static inline u16 ntohs(u16 x)
|
||||
{
|
||||
if (little_endian)
|
||||
return
|
||||
( (((x) >> 8) & 0xff )|
|
||||
(((x) << 8) & 0xff00 ) );
|
||||
( (((x) >> 8) & 0xff )|
|
||||
(((x) << 8) & 0xff00 ) );
|
||||
else
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
|
||||
#define htonl(x) ntohl(x)
|
||||
@@ -55,8 +56,8 @@ static inline void arrcpy16(u16 *dest, const u16 *src, size_t n)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
while (i < n) {
|
||||
dest[i] = htons(src[i]);
|
||||
i++;
|
||||
dest[i] = htons(src[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +65,8 @@ static inline void arrcpy32(u32 *dest, const u32 *src, size_t n)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
while (i < n) {
|
||||
dest[i] = htonl(src[i]);
|
||||
i++;
|
||||
dest[i] = htonl(src[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,3 +87,13 @@ static inline void arrcpy(void *dest, const void *src, unsigned int elsize, size
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -15,6 +15,7 @@
|
||||
* sHype hooks that are called throughout Xen.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ACM_HOOKS_H
|
||||
#define _ACM_HOOKS_H
|
||||
|
||||
@@ -89,8 +90,8 @@ struct acm_operations {
|
||||
/* policy management functions (must always be defined!) */
|
||||
int (*init_domain_ssid) (void **ssid, ssidref_t ssidref);
|
||||
void (*free_domain_ssid) (void *ssid);
|
||||
int (*dump_binary_policy) (u8 *buffer, u16 buf_size);
|
||||
int (*set_binary_policy) (u8 *buffer, u16 buf_size);
|
||||
int (*dump_binary_policy) (u8 *buffer, u32 buf_size);
|
||||
int (*set_binary_policy) (u8 *buffer, u32 buf_size);
|
||||
int (*dump_statistics) (u8 *buffer, u16 buf_size);
|
||||
int (*dump_ssid_types) (ssidref_t ssidref, u8 *buffer, u16 buf_size);
|
||||
/* domain management control hooks (can be NULL) */
|
||||
@@ -108,6 +109,8 @@ struct acm_operations {
|
||||
void (*fail_grant_map_ref) (domid_t id);
|
||||
int (*pre_grant_setup) (domid_t id);
|
||||
void (*fail_grant_setup) (domid_t id);
|
||||
/* generic domain-requested decision hooks (can be NULL) */
|
||||
int (*sharing) (ssidref_t ssidref1, ssidref_t ssidref2);
|
||||
};
|
||||
|
||||
/* global variables */
|
||||
@@ -144,6 +147,8 @@ static inline int acm_init(unsigned int *initrdidx,
|
||||
{ return 0; }
|
||||
static inline void acm_post_domain0_create(domid_t domid)
|
||||
{ return; }
|
||||
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
|
||||
{ return 0; }
|
||||
|
||||
#else
|
||||
|
||||
@@ -281,7 +286,8 @@ static inline int acm_pre_event_channel(evtchn_op_t *op)
|
||||
break;
|
||||
case EVTCHNOP_bind_interdomain:
|
||||
ret = acm_pre_eventchannel_interdomain(
|
||||
op->u.bind_interdomain.dom1, op->u.bind_interdomain.dom2);
|
||||
current->domain->domain_id,
|
||||
op->u.bind_interdomain.remote_dom);
|
||||
break;
|
||||
default:
|
||||
ret = 0; /* ok */
|
||||
@@ -341,6 +347,18 @@ static inline void acm_post_domain0_create(domid_t domid)
|
||||
acm_post_domain_create(domid, ACM_DOM0_SSIDREF);
|
||||
}
|
||||
|
||||
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
|
||||
{
|
||||
if ((acm_primary_ops->sharing != NULL) &&
|
||||
acm_primary_ops->sharing(ssidref1, ssidref2))
|
||||
return ACM_ACCESS_DENIED;
|
||||
else if ((acm_secondary_ops->sharing != NULL) &&
|
||||
acm_secondary_ops->sharing(ssidref1, ssidref2)) {
|
||||
return ACM_ACCESS_DENIED;
|
||||
} else
|
||||
return ACM_ACCESS_PERMITTED;
|
||||
}
|
||||
|
||||
extern int acm_init(unsigned int *initrdidx,
|
||||
const multiboot_info_t *mbi,
|
||||
unsigned long start);
|
||||
@@ -348,3 +366,13 @@ extern int acm_init(unsigned int *initrdidx,
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-set-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -52,9 +52,9 @@
|
||||
#define ACM_ERROR -4
|
||||
|
||||
/* External ACCESS DECISIONS */
|
||||
#define ACM_ACCESS_PERMITTED 0
|
||||
#define ACM_ACCESS_DENIED -111
|
||||
#define ACM_NULL_POINTER_ERROR -200
|
||||
#define ACM_ACCESS_PERMITTED 0
|
||||
#define ACM_ACCESS_DENIED -111
|
||||
#define ACM_NULL_POINTER_ERROR -200
|
||||
|
||||
/* primary policy in lower 4 bits */
|
||||
#define ACM_NULL_POLICY 0
|
||||
@@ -84,6 +84,9 @@
|
||||
/* defines a ssid reference used by xen */
|
||||
typedef uint32_t ssidref_t;
|
||||
|
||||
/* hooks that are known to domains */
|
||||
enum acm_hook_type {NONE=0, SHARING};
|
||||
|
||||
/* -------security policy relevant type definitions-------- */
|
||||
|
||||
/* type identifier; compares to "equal" or "not equal" */
|
||||
|
||||
@@ -27,36 +27,36 @@
|
||||
* This makes sure that old versions of acm tools will stop working in a
|
||||
* well-defined way (rather than crashing the machine, for instance).
|
||||
*/
|
||||
#define ACM_INTERFACE_VERSION 0xAAAA0004
|
||||
#define ACM_INTERFACE_VERSION 0xAAAA0005
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
#define ACM_SETPOLICY 4
|
||||
typedef struct acm_setpolicy {
|
||||
struct acm_setpolicy {
|
||||
/* OUT variables */
|
||||
void *pushcache;
|
||||
uint16_t pushcache_size;
|
||||
} acm_setpolicy_t;
|
||||
uint32_t pushcache_size;
|
||||
};
|
||||
|
||||
|
||||
#define ACM_GETPOLICY 5
|
||||
typedef struct acm_getpolicy {
|
||||
struct acm_getpolicy {
|
||||
/* OUT variables */
|
||||
void *pullcache;
|
||||
uint16_t pullcache_size;
|
||||
} acm_getpolicy_t;
|
||||
uint32_t pullcache_size;
|
||||
};
|
||||
|
||||
|
||||
#define ACM_DUMPSTATS 6
|
||||
typedef struct acm_dumpstats {
|
||||
struct acm_dumpstats {
|
||||
void *pullcache;
|
||||
uint16_t pullcache_size;
|
||||
} acm_dumpstats_t;
|
||||
uint32_t pullcache_size;
|
||||
};
|
||||
|
||||
|
||||
#define ACM_GETSSID 7
|
||||
enum get_type {UNSET, SSIDREF, DOMAINID};
|
||||
typedef struct acm_getssid {
|
||||
enum get_type {UNSET=0, SSIDREF, DOMAINID};
|
||||
struct acm_getssid {
|
||||
enum get_type get_ssid_by;
|
||||
union {
|
||||
domaintype_t domainid;
|
||||
@@ -64,18 +64,35 @@ typedef struct acm_getssid {
|
||||
} id;
|
||||
void *ssidbuf;
|
||||
uint16_t ssidbuf_size;
|
||||
} acm_getssid_t;
|
||||
};
|
||||
|
||||
typedef struct acm_op {
|
||||
#define ACM_GETDECISION 8
|
||||
struct acm_getdecision {
|
||||
enum get_type get_decision_by1; /* in */
|
||||
enum get_type get_decision_by2;
|
||||
union {
|
||||
domaintype_t domainid;
|
||||
ssidref_t ssidref;
|
||||
} id1;
|
||||
union {
|
||||
domaintype_t domainid;
|
||||
ssidref_t ssidref;
|
||||
} id2;
|
||||
enum acm_hook_type hook;
|
||||
int acm_decision; /* out */
|
||||
};
|
||||
|
||||
struct acm_op {
|
||||
uint32_t cmd;
|
||||
uint32_t interface_version; /* ACM_INTERFACE_VERSION */
|
||||
union {
|
||||
acm_setpolicy_t setpolicy;
|
||||
acm_getpolicy_t getpolicy;
|
||||
acm_dumpstats_t dumpstats;
|
||||
acm_getssid_t getssid;
|
||||
struct acm_setpolicy setpolicy;
|
||||
struct acm_getpolicy getpolicy;
|
||||
struct acm_dumpstats dumpstats;
|
||||
struct acm_getssid getssid;
|
||||
struct acm_getdecision getdecision;
|
||||
} u;
|
||||
} acm_op_t;
|
||||
};
|
||||
|
||||
#endif /* __XEN_PUBLIC_ACM_OPS_H__ */
|
||||
|
||||
|
||||