1 /******************************************************************************
2 * xc_flask.c
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation;
7 * version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "xc_private.h"
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <sys/mman.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <sys/ioctl.h>
29
30 #define OCON_ISID 0 /* initial SIDs */
31 #define OCON_PIRQ 1 /* physical irqs */
32 #define OCON_IOPORT 2 /* io ports */
33 #define OCON_IOMEM 3 /* io memory */
34 #define OCON_DEVICE 4 /* pci devices */
35 #define INITCONTEXTLEN 256
36
xc_flask_op(xc_interface * xch,xen_flask_op_t * op)37 int xc_flask_op(xc_interface *xch, xen_flask_op_t *op)
38 {
39 int ret = -1;
40 DECLARE_HYPERCALL_BOUNCE(op, sizeof(*op), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
41
42 op->interface_version = XEN_FLASK_INTERFACE_VERSION;
43
44 if ( xc_hypercall_bounce_pre(xch, op) )
45 {
46 PERROR("Could not bounce memory for flask op hypercall");
47 goto out;
48 }
49
50 ret = xencall1(xch->xcall, __HYPERVISOR_xsm_op,
51 HYPERCALL_BUFFER_AS_ARG(op));
52 if ( ret < 0 )
53 {
54 if ( errno == EACCES )
55 fprintf(stderr, "XSM operation failed!\n");
56 }
57
58 xc_hypercall_bounce_post(xch, op);
59
60 out:
61 return ret;
62 }
63
xc_flask_load(xc_interface * xch,char * buf,uint32_t size)64 int xc_flask_load(xc_interface *xch, char *buf, uint32_t size)
65 {
66 int err;
67 DECLARE_FLASK_OP;
68 DECLARE_HYPERCALL_BOUNCE(buf, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
69 if ( xc_hypercall_bounce_pre(xch, buf) )
70 {
71 PERROR("Could not bounce memory for flask op hypercall");
72 return -1;
73 }
74
75 op.cmd = FLASK_LOAD;
76 op.u.load.size = size;
77 set_xen_guest_handle(op.u.load.buffer, buf);
78
79 err = xc_flask_op(xch, &op);
80
81 xc_hypercall_bounce_post(xch, buf);
82
83 return err;
84 }
85
xc_flask_context_to_sid(xc_interface * xch,char * buf,uint32_t size,uint32_t * sid)86 int xc_flask_context_to_sid(xc_interface *xch, char *buf, uint32_t size, uint32_t *sid)
87 {
88 int err;
89 DECLARE_FLASK_OP;
90 DECLARE_HYPERCALL_BOUNCE(buf, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
91
92 if ( xc_hypercall_bounce_pre(xch, buf) )
93 {
94 PERROR("Could not bounce memory for flask op hypercall");
95 return -1;
96 }
97
98 op.cmd = FLASK_CONTEXT_TO_SID;
99 op.u.sid_context.size = size;
100 set_xen_guest_handle(op.u.sid_context.context, buf);
101
102 err = xc_flask_op(xch, &op);
103
104 if ( !err )
105 *sid = op.u.sid_context.sid;
106
107 xc_hypercall_bounce_post(xch, buf);
108
109 return err;
110 }
111
xc_flask_sid_to_context(xc_interface * xch,int sid,char * buf,uint32_t size)112 int xc_flask_sid_to_context(xc_interface *xch, int sid, char *buf, uint32_t size)
113 {
114 int err;
115 DECLARE_FLASK_OP;
116 DECLARE_HYPERCALL_BOUNCE(buf, size, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
117
118 if ( xc_hypercall_bounce_pre(xch, buf) )
119 {
120 PERROR("Could not bounce memory for flask op hypercall");
121 return -1;
122 }
123
124 op.cmd = FLASK_SID_TO_CONTEXT;
125 op.u.sid_context.sid = sid;
126 op.u.sid_context.size = size;
127 set_xen_guest_handle(op.u.sid_context.context, buf);
128
129 err = xc_flask_op(xch, &op);
130
131 xc_hypercall_bounce_post(xch, buf);
132
133 return err;
134 }
135
xc_flask_getenforce(xc_interface * xch)136 int xc_flask_getenforce(xc_interface *xch)
137 {
138 DECLARE_FLASK_OP;
139 op.cmd = FLASK_GETENFORCE;
140
141 return xc_flask_op(xch, &op);
142 }
143
xc_flask_setenforce(xc_interface * xch,int mode)144 int xc_flask_setenforce(xc_interface *xch, int mode)
145 {
146 DECLARE_FLASK_OP;
147 op.cmd = FLASK_SETENFORCE;
148 op.u.enforce.enforcing = mode;
149
150 return xc_flask_op(xch, &op);
151 }
152
xc_flask_getbool_byid(xc_interface * xch,int id,char * name,uint32_t size,int * curr,int * pend)153 int xc_flask_getbool_byid(xc_interface *xch, int id, char *name, uint32_t size, int *curr, int *pend)
154 {
155 int rv;
156 DECLARE_FLASK_OP;
157 DECLARE_HYPERCALL_BOUNCE(name, size, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
158
159 if ( xc_hypercall_bounce_pre(xch, name) )
160 {
161 PERROR("Could not bounce memory for flask op hypercall");
162 return -1;
163 }
164
165 op.cmd = FLASK_GETBOOL;
166 op.u.boolean.bool_id = id;
167 op.u.boolean.size = size;
168 set_xen_guest_handle(op.u.boolean.name, name);
169
170 rv = xc_flask_op(xch, &op);
171
172 xc_hypercall_bounce_post(xch, name);
173
174 if ( rv )
175 return rv;
176
177 if ( curr )
178 *curr = op.u.boolean.enforcing;
179 if ( pend )
180 *pend = op.u.boolean.pending;
181
182 return rv;
183 }
184
xc_flask_getbool_byname(xc_interface * xch,char * name,int * curr,int * pend)185 int xc_flask_getbool_byname(xc_interface *xch, char *name, int *curr, int *pend)
186 {
187 int rv;
188 DECLARE_FLASK_OP;
189 DECLARE_HYPERCALL_BOUNCE(name, strlen(name), XC_HYPERCALL_BUFFER_BOUNCE_IN);
190
191 if ( xc_hypercall_bounce_pre(xch, name) )
192 {
193 PERROR("Could not bounce memory for flask op hypercall");
194 return -1;
195 }
196
197 op.cmd = FLASK_GETBOOL;
198 op.u.boolean.bool_id = -1;
199 op.u.boolean.size = strlen(name);
200 set_xen_guest_handle(op.u.boolean.name, name);
201
202 rv = xc_flask_op(xch, &op);
203
204 xc_hypercall_bounce_post(xch, name);
205
206 if ( rv )
207 return rv;
208
209 if ( curr )
210 *curr = op.u.boolean.enforcing;
211 if ( pend )
212 *pend = op.u.boolean.pending;
213
214 return rv;
215 }
216
xc_flask_setbool(xc_interface * xch,char * name,int value,int commit)217 int xc_flask_setbool(xc_interface *xch, char *name, int value, int commit)
218 {
219 int rv;
220 DECLARE_FLASK_OP;
221 DECLARE_HYPERCALL_BOUNCE(name, strlen(name), XC_HYPERCALL_BUFFER_BOUNCE_IN);
222
223 if ( xc_hypercall_bounce_pre(xch, name) )
224 {
225 PERROR("Could not bounce memory for flask op hypercall");
226 return -1;
227 }
228
229 op.cmd = FLASK_SETBOOL;
230 op.u.boolean.bool_id = -1;
231 op.u.boolean.new_value = value;
232 op.u.boolean.commit = 1;
233 op.u.boolean.size = strlen(name);
234 set_xen_guest_handle(op.u.boolean.name, name);
235
236 rv = xc_flask_op(xch, &op);
237
238 xc_hypercall_bounce_post(xch, name);
239
240 return rv;
241 }
242
243
xc_flask_add(xc_interface * xch,uint32_t ocon,uint64_t low,uint64_t high,char * scontext)244 static int xc_flask_add(xc_interface *xch, uint32_t ocon, uint64_t low, uint64_t high, char *scontext)
245 {
246 uint32_t sid;
247 int err;
248 DECLARE_FLASK_OP;
249
250 err = xc_flask_context_to_sid(xch, scontext, strlen(scontext), &sid);
251 if ( err )
252 return err;
253
254 op.cmd = FLASK_ADD_OCONTEXT;
255 op.u.ocontext.ocon = ocon;
256 op.u.ocontext.sid = sid;
257 op.u.ocontext.low = low;
258 op.u.ocontext.high = high;
259
260 return xc_flask_op(xch, &op);
261 }
262
xc_flask_add_pirq(xc_interface * xch,unsigned int pirq,char * scontext)263 int xc_flask_add_pirq(xc_interface *xch, unsigned int pirq, char *scontext)
264 {
265 return xc_flask_add(xch, OCON_PIRQ, pirq, pirq, scontext);
266 }
267
xc_flask_add_ioport(xc_interface * xch,unsigned long low,unsigned long high,char * scontext)268 int xc_flask_add_ioport(xc_interface *xch, unsigned long low, unsigned long high,
269 char *scontext)
270 {
271 return xc_flask_add(xch, OCON_IOPORT, low, high, scontext);
272 }
273
xc_flask_add_iomem(xc_interface * xch,unsigned long low,unsigned long high,char * scontext)274 int xc_flask_add_iomem(xc_interface *xch, unsigned long low, unsigned long high,
275 char *scontext)
276 {
277 return xc_flask_add(xch, OCON_IOMEM, low, high, scontext);
278 }
279
xc_flask_add_device(xc_interface * xch,unsigned long device,char * scontext)280 int xc_flask_add_device(xc_interface *xch, unsigned long device, char *scontext)
281 {
282 return xc_flask_add(xch, OCON_DEVICE, device, device, scontext);
283 }
284
xc_flask_del(xc_interface * xch,uint32_t ocon,uint64_t low,uint64_t high)285 static int xc_flask_del(xc_interface *xch, uint32_t ocon, uint64_t low, uint64_t high)
286 {
287 DECLARE_FLASK_OP;
288
289 op.cmd = FLASK_DEL_OCONTEXT;
290 op.u.ocontext.ocon = ocon;
291 op.u.ocontext.low = low;
292 op.u.ocontext.high = high;
293
294 return xc_flask_op(xch, &op);
295 }
296
xc_flask_del_pirq(xc_interface * xch,unsigned int pirq)297 int xc_flask_del_pirq(xc_interface *xch, unsigned int pirq)
298 {
299 return xc_flask_del(xch, OCON_PIRQ, pirq, pirq);
300 }
301
xc_flask_del_ioport(xc_interface * xch,unsigned long low,unsigned long high)302 int xc_flask_del_ioport(xc_interface *xch, unsigned long low, unsigned long high)
303 {
304 return xc_flask_del(xch, OCON_IOPORT, low, high);
305 }
306
xc_flask_del_iomem(xc_interface * xch,unsigned long low,unsigned long high)307 int xc_flask_del_iomem(xc_interface *xch, unsigned long low, unsigned long high)
308 {
309 return xc_flask_del(xch, OCON_IOMEM, low, high);
310 }
311
xc_flask_del_device(xc_interface * xch,unsigned long device)312 int xc_flask_del_device(xc_interface *xch, unsigned long device)
313 {
314 return xc_flask_del(xch, OCON_DEVICE, device, device);
315 }
316
xc_flask_access(xc_interface * xch,const char * scon,const char * tcon,uint16_t tclass,uint32_t req,uint32_t * allowed,uint32_t * decided,uint32_t * auditallow,uint32_t * auditdeny,uint32_t * seqno)317 int xc_flask_access(xc_interface *xch, const char *scon, const char *tcon,
318 uint16_t tclass, uint32_t req,
319 uint32_t *allowed, uint32_t *decided,
320 uint32_t *auditallow, uint32_t *auditdeny,
321 uint32_t *seqno)
322 {
323 DECLARE_FLASK_OP;
324 int err;
325
326 err = xc_flask_context_to_sid(xch, (char*)scon, strlen(scon), &op.u.access.ssid);
327 if ( err )
328 return err;
329 err = xc_flask_context_to_sid(xch, (char*)tcon, strlen(tcon), &op.u.access.tsid);
330 if ( err )
331 return err;
332
333 op.cmd = FLASK_ACCESS;
334 op.u.access.tclass = tclass;
335 op.u.access.req = req;
336
337 err = xc_flask_op(xch, &op);
338
339 if ( err )
340 return err;
341
342 if ( allowed )
343 *allowed = op.u.access.allowed;
344 if ( decided )
345 *decided = 0xffffffff;
346 if ( auditallow )
347 *auditallow = op.u.access.audit_allow;
348 if ( auditdeny )
349 *auditdeny = op.u.access.audit_deny;
350 if ( seqno )
351 *seqno = op.u.access.seqno;
352
353 if ( (op.u.access.allowed & req) != req )
354 err = -EPERM;
355
356 return err;
357 }
358
xc_flask_avc_hashstats(xc_interface * xch,char * buf,int size)359 int xc_flask_avc_hashstats(xc_interface *xch, char *buf, int size)
360 {
361 int err;
362 DECLARE_FLASK_OP;
363
364 op.cmd = FLASK_AVC_HASHSTATS;
365
366 err = xc_flask_op(xch, &op);
367
368 snprintf(buf, size,
369 "entries: %d\nbuckets used: %d/%d\nlongest chain: %d\n",
370 op.u.hash_stats.entries, op.u.hash_stats.buckets_used,
371 op.u.hash_stats.buckets_total, op.u.hash_stats.max_chain_len);
372
373 return err;
374 }
375
xc_flask_avc_cachestats(xc_interface * xch,char * buf,int size)376 int xc_flask_avc_cachestats(xc_interface *xch, char *buf, int size)
377 {
378 int err, n;
379 int i = 0;
380 DECLARE_FLASK_OP;
381
382 n = snprintf(buf, size, "lookups hits misses allocations reclaims frees\n");
383 buf += n;
384 size -= n;
385
386 op.cmd = FLASK_AVC_CACHESTATS;
387 while ( size > 0 )
388 {
389 op.u.cache_stats.cpu = i;
390 err = xc_flask_op(xch, &op);
391 if ( err && errno == ENOENT )
392 return 0;
393 if ( err )
394 return err;
395 n = snprintf(buf, size, "%u %u %u %u %u %u\n",
396 op.u.cache_stats.lookups, op.u.cache_stats.hits,
397 op.u.cache_stats.misses, op.u.cache_stats.allocations,
398 op.u.cache_stats.reclaims, op.u.cache_stats.frees);
399 buf += n;
400 size -= n;
401 i++;
402 }
403
404 return 0;
405 }
406
xc_flask_policyvers(xc_interface * xch)407 int xc_flask_policyvers(xc_interface *xch)
408 {
409 DECLARE_FLASK_OP;
410 op.cmd = FLASK_POLICYVERS;
411
412 return xc_flask_op(xch, &op);
413 }
414
xc_flask_getavc_threshold(xc_interface * xch)415 int xc_flask_getavc_threshold(xc_interface *xch)
416 {
417 DECLARE_FLASK_OP;
418 op.cmd = FLASK_GETAVC_THRESHOLD;
419
420 return xc_flask_op(xch, &op);
421 }
422
xc_flask_setavc_threshold(xc_interface * xch,int threshold)423 int xc_flask_setavc_threshold(xc_interface *xch, int threshold)
424 {
425 DECLARE_FLASK_OP;
426 op.cmd = FLASK_SETAVC_THRESHOLD;
427 op.u.setavc_threshold.threshold = threshold;
428
429 return xc_flask_op(xch, &op);
430 }
431
xc_flask_relabel_domain(xc_interface * xch,uint32_t domid,uint32_t sid)432 int xc_flask_relabel_domain(xc_interface *xch, uint32_t domid, uint32_t sid)
433 {
434 DECLARE_FLASK_OP;
435 op.cmd = FLASK_RELABEL_DOMAIN;
436 op.u.relabel.domid = domid;
437 op.u.relabel.sid = sid;
438
439 return xc_flask_op(xch, &op);
440 }
441
442 /*
443 * Local variables:
444 * mode: C
445 * c-file-style: "BSD"
446 * c-basic-offset: 4
447 * tab-width: 4
448 * indent-tabs-mode: nil
449 * End:
450 */
451