1
/****************************************************************
4
* Copyright (C) 2005 IBM Corporation
7
* Reiner Sailer <sailer@watson.ibm.com>
9
* This program is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU General Public License as
11
* published by the Free Software Foundation, version 2 of the
14
* acm header file implementing the global (policy-independent)
15
* sHype hooks that are called throughout Xen.
22
#include <xen/config.h>
23
#include <xen/errno.h>
24
#include <xen/types.h>
26
#include <xen/delay.h>
27
#include <xen/sched.h>
28
#include <xen/multiboot.h>
29
#include <public/xsm/acm.h>
30
#include <xsm/acm/acm_core.h>
31
#include <public/domctl.h>
32
#include <public/event_channel.h>
33
#include <asm/current.h>
36
* HOOK structure and meaning (justifies a few words about our model):
38
* General idea: every policy-controlled system operation is reflected in a
39
* transaction in the system's security state
41
* Keeping the security state consistent requires "atomic" transactions.
42
* The name of the hooks to place around policy-controlled transactions
43
* reflects this. If authorizations do not involve security state changes,
44
* then and only then POST and FAIL hooks remain empty since we don't care
45
* about the eventual outcome of the operation from a security viewpoint.
47
* PURPOSE of hook types:
48
* ======================
50
* a) general authorization to guard a controlled system operation
51
* b) prepare security state change
52
* (means: fail hook must be able to "undo" this)
55
* a) commit prepared state change
58
* a) roll-back prepared security state change from PRE-Hook
61
* PLACEMENT of hook types:
62
* ========================
63
* PRE-Hooks must be called before a guarded/controlled system operation
64
* is started. They return ACM_ACCESS_PERMITTED, ACM_ACCESS_DENIED or
65
* error. Operation must be aborted if return is not ACM_ACCESS_PERMITTED.
67
* POST-Hooks must be called after a successful system operation.
68
* There is no return value: commit never fails.
70
* FAIL-Hooks must be called:
71
* a) if system transaction (operation) fails after calling the PRE-hook
72
* b) if another (secondary) policy denies access in its PRE-Hook
73
* (policy layering is useful but requires additional handling)
75
* Hook model from a security transaction viewpoint:
76
* start-sys-ops--> prepare ----succeed-----> commit --> sys-ops success
77
* (pre-hook) \ (post-hook)
89
struct acm_operations {
90
/* policy management functions (must always be defined!) */
91
int (*init_domain_ssid) (void **ssid, ssidref_t ssidref);
92
void (*free_domain_ssid) (void *ssid);
93
int (*dump_binary_policy) (u8 *buffer, u32 buf_size);
94
int (*test_binary_policy) (u8 *buffer, u32 buf_size,
96
struct acm_sized_buffer *);
97
int (*set_binary_policy) (u8 *buffer, u32 buf_size);
98
int (*dump_statistics) (u8 *buffer, u16 buf_size);
99
int (*dump_ssid_types) (ssidref_t ssidref, u8 *buffer, u16 buf_size);
100
/* domain management control hooks (can be NULL) */
101
int (*domain_create) (void *subject_ssid, ssidref_t ssidref,
103
void (*domain_destroy) (void *object_ssid, struct domain *d);
104
/* event channel control hooks (can be NULL) */
105
int (*pre_eventchannel_unbound) (domid_t id1, domid_t id2);
106
void (*fail_eventchannel_unbound) (domid_t id1, domid_t id2);
107
int (*pre_eventchannel_interdomain) (domid_t id);
108
void (*fail_eventchannel_interdomain) (domid_t id);
109
/* grant table control hooks (can be NULL) */
110
int (*pre_grant_map_ref) (domid_t id);
111
void (*fail_grant_map_ref) (domid_t id);
112
int (*pre_grant_setup) (domid_t id);
113
void (*fail_grant_setup) (domid_t id);
114
/* generic domain-requested decision hooks (can be NULL) */
115
int (*sharing) (ssidref_t ssidref1,
117
int (*authorization) (ssidref_t ssidref1,
119
int (*conflictset) (ssidref_t ssidref1);
120
/* determine whether the default policy is installed */
121
int (*is_default_policy) (void);
124
/* global variables */
125
extern struct acm_operations *acm_primary_ops;
126
extern struct acm_operations *acm_secondary_ops;
128
/* if ACM_TRACE_MODE defined, all hooks should
129
* print a short trace message */
130
/* #define ACM_TRACE_MODE */
132
#ifdef ACM_TRACE_MODE
133
# define traceprintk(fmt, args...) printk(fmt, ## args)
135
# define traceprintk(fmt, args...)
138
/* if ACM_DEBUG defined, all hooks should
139
* print a short trace message (comment it out
140
* when not in testing mode )
142
/* #define ACM_DEBUG */
145
# define printkd(fmt, args...) printk(fmt, ## args)
147
# define printkd(fmt, args...)
152
static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
154
static inline int acm_pre_eventchannel_interdomain(domid_t id)
156
static inline int acm_pre_grant_map_ref(domid_t id)
158
static inline int acm_pre_grant_setup(domid_t id)
160
static inline int acm_is_policy(char *buf, unsigned long len)
162
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
164
static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
166
static inline int acm_conflictset(ssidref_t ssidref1)
168
static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
170
static inline void acm_domain_destroy(struct domain *d)
173
#define DOM0_SSIDREF 0x0
177
static inline void acm_domain_ssid_onto_list(struct acm_ssid_domain *ssid)
179
write_lock(&ssid_list_rwlock);
180
list_add(&ssid->node, &ssid_list);
181
write_unlock(&ssid_list_rwlock);
184
static inline void acm_domain_ssid_off_list(struct acm_ssid_domain *ssid)
186
write_lock(&ssid_list_rwlock);
187
list_del(&ssid->node);
188
write_unlock(&ssid_list_rwlock);
191
static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
193
if ((acm_primary_ops->pre_eventchannel_unbound != NULL) &&
194
acm_primary_ops->pre_eventchannel_unbound(id1, id2))
195
return ACM_ACCESS_DENIED;
196
else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) &&
197
acm_secondary_ops->pre_eventchannel_unbound(id1, id2)) {
198
/* roll-back primary */
199
if (acm_primary_ops->fail_eventchannel_unbound != NULL)
200
acm_primary_ops->fail_eventchannel_unbound(id1, id2);
201
return ACM_ACCESS_DENIED;
203
return ACM_ACCESS_PERMITTED;
206
static inline int acm_pre_eventchannel_interdomain(domid_t id)
208
if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) &&
209
acm_primary_ops->pre_eventchannel_interdomain(id))
210
return ACM_ACCESS_DENIED;
211
else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) &&
212
acm_secondary_ops->pre_eventchannel_interdomain(id)) {
213
/* roll-back primary */
214
if (acm_primary_ops->fail_eventchannel_interdomain != NULL)
215
acm_primary_ops->fail_eventchannel_interdomain(id);
216
return ACM_ACCESS_DENIED;
218
return ACM_ACCESS_PERMITTED;
222
static inline int acm_pre_grant_map_ref(domid_t id)
224
if ( (acm_primary_ops->pre_grant_map_ref != NULL) &&
225
acm_primary_ops->pre_grant_map_ref(id) )
227
return ACM_ACCESS_DENIED;
229
else if ( (acm_secondary_ops->pre_grant_map_ref != NULL) &&
230
acm_secondary_ops->pre_grant_map_ref(id) )
232
/* roll-back primary */
233
if ( acm_primary_ops->fail_grant_map_ref != NULL )
234
acm_primary_ops->fail_grant_map_ref(id);
235
return ACM_ACCESS_DENIED;
239
return ACM_ACCESS_PERMITTED;
243
static inline int acm_pre_grant_setup(domid_t id)
245
if ( (acm_primary_ops->pre_grant_setup != NULL) &&
246
acm_primary_ops->pre_grant_setup(id) )
248
return ACM_ACCESS_DENIED;
250
else if ( (acm_secondary_ops->pre_grant_setup != NULL) &&
251
acm_secondary_ops->pre_grant_setup(id) )
253
/* roll-back primary */
254
if (acm_primary_ops->fail_grant_setup != NULL)
255
acm_primary_ops->fail_grant_setup(id);
256
return ACM_ACCESS_DENIED;
260
return ACM_ACCESS_PERMITTED;
265
static inline void acm_domain_destroy(struct domain *d)
267
void *ssid = d->ssid;
269
if (acm_primary_ops->domain_destroy != NULL)
270
acm_primary_ops->domain_destroy(ssid, d);
271
if (acm_secondary_ops->domain_destroy != NULL)
272
acm_secondary_ops->domain_destroy(ssid, d);
273
/* free security ssid for the destroyed domain (also if null policy */
274
acm_domain_ssid_off_list(ssid);
275
acm_free_domain_ssid(d);
280
static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
282
void *subject_ssid = current->domain->ssid;
283
domid_t domid = d->domain_id;
286
read_lock(&acm_bin_pol_rwlock);
288
To be called when a domain is created; returns '0' if the
289
domain is allowed to be created, != '0' if not.
291
rc = acm_init_domain_ssid(d, ssidref);
295
if ((acm_primary_ops->domain_create != NULL) &&
296
acm_primary_ops->domain_create(subject_ssid, ssidref, domid)) {
297
rc = ACM_ACCESS_DENIED;
298
} else if ((acm_secondary_ops->domain_create != NULL) &&
299
acm_secondary_ops->domain_create(subject_ssid, ssidref,
301
/* roll-back primary */
302
if (acm_primary_ops->domain_destroy != NULL)
303
acm_primary_ops->domain_destroy(d->ssid, d);
304
rc = ACM_ACCESS_DENIED;
309
acm_domain_ssid_onto_list(d->ssid);
311
acm_free_domain_ssid(d);
315
read_unlock(&acm_bin_pol_rwlock);
320
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
322
if ((acm_primary_ops->sharing != NULL) &&
323
acm_primary_ops->sharing(ssidref1, ssidref2))
324
return ACM_ACCESS_DENIED;
325
else if ((acm_secondary_ops->sharing != NULL) &&
326
acm_secondary_ops->sharing(ssidref1, ssidref2)) {
327
return ACM_ACCESS_DENIED;
329
return ACM_ACCESS_PERMITTED;
333
static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
335
if ((acm_primary_ops->authorization != NULL) &&
336
acm_primary_ops->authorization(ssidref1, ssidref2))
337
return ACM_ACCESS_DENIED;
338
else if ((acm_secondary_ops->authorization != NULL) &&
339
acm_secondary_ops->authorization(ssidref1, ssidref2)) {
340
return ACM_ACCESS_DENIED;
342
return acm_sharing(ssidref1, ssidref2);
346
static inline int acm_conflictset(ssidref_t ssidref1)
348
if ((acm_primary_ops->conflictset != NULL) &&
349
acm_primary_ops->conflictset(ssidref1))
350
return ACM_ACCESS_DENIED;
351
else if ((acm_secondary_ops->conflictset != NULL) &&
352
acm_secondary_ops->conflictset(ssidref1))
353
return ACM_ACCESS_DENIED;
354
return ACM_ACCESS_PERMITTED;
357
/* Return true iff buffer has an acm policy magic number. */
358
extern int acm_is_policy(char *buf, unsigned long len);
360
#define DOM0_SSIDREF (dom0_ste_ssidref << 16 | dom0_chwall_ssidref)
372
* indent-tabs-mode: nil