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