1 /*
2 * This file contains the flask_op hypercall and associated functions.
3 *
4 * Author: George Coker, <gscoker@alpha.ncsc.mil>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2,
8 * as published by the Free Software Foundation.
9 */
10 #ifndef COMPAT
11 #include <xen/errno.h>
12 #include <xen/event.h>
13 #include <xsm/xsm.h>
14 #include <xen/guest_access.h>
15 #include <xen/err.h>
16
17 #include <public/xsm/flask_op.h>
18
19 #include <avc.h>
20 #include <avc_ss.h>
21 #include <objsec.h>
22 #include <conditional.h>
23
24 #define ret_t long
25 #define _copy_to_guest copy_to_guest
26 #define _copy_from_guest copy_from_guest
27
28 enum flask_bootparam_t __read_mostly flask_bootparam = FLASK_BOOTPARAM_ENFORCING;
29 static int parse_flask_param(const char *s);
30 custom_param("flask", parse_flask_param);
31
32 bool __read_mostly flask_enforcing = true;
33
34 #define MAX_POLICY_SIZE 0x4000000
35
36 #define FLASK_COPY_OUT \
37 ( \
38 1UL<<FLASK_CONTEXT_TO_SID | \
39 1UL<<FLASK_SID_TO_CONTEXT | \
40 1UL<<FLASK_ACCESS | \
41 1UL<<FLASK_CREATE | \
42 1UL<<FLASK_RELABEL | \
43 1UL<<FLASK_USER | \
44 1UL<<FLASK_GETBOOL | \
45 1UL<<FLASK_SETBOOL | \
46 1UL<<FLASK_AVC_HASHSTATS | \
47 1UL<<FLASK_AVC_CACHESTATS | \
48 1UL<<FLASK_MEMBER | \
49 1UL<<FLASK_GET_PEER_SID | \
50 0)
51
52 static DEFINE_SPINLOCK(sel_sem);
53
54 /* global data for booleans */
55 static int bool_num = 0;
56 static int *bool_pending_values = NULL;
57 static int flask_security_make_bools(void);
58
59 extern int ss_initialized;
60
parse_flask_param(const char * s)61 static int __init parse_flask_param(const char *s)
62 {
63 if ( !strcmp(s, "enforcing") )
64 flask_bootparam = FLASK_BOOTPARAM_ENFORCING;
65 else if ( !strcmp(s, "late") )
66 flask_bootparam = FLASK_BOOTPARAM_LATELOAD;
67 else if ( !strcmp(s, "disabled") )
68 flask_bootparam = FLASK_BOOTPARAM_DISABLED;
69 else if ( !strcmp(s, "permissive") )
70 flask_bootparam = FLASK_BOOTPARAM_PERMISSIVE;
71 else
72 flask_bootparam = FLASK_BOOTPARAM_INVALID;
73
74 return (flask_bootparam == FLASK_BOOTPARAM_INVALID) ? -EINVAL : 0;
75 }
76
domain_has_security(struct domain * d,u32 perms)77 static int domain_has_security(struct domain *d, u32 perms)
78 {
79 struct domain_security_struct *dsec;
80
81 dsec = d->ssid;
82 if ( !dsec )
83 return -EACCES;
84
85 return avc_has_perm(dsec->sid, SECINITSID_SECURITY, SECCLASS_SECURITY,
86 perms, NULL);
87 }
88
flask_security_relabel(struct xen_flask_transition * arg)89 static int flask_security_relabel(struct xen_flask_transition *arg)
90 {
91 int rv;
92
93 rv = domain_has_security(current->domain, SECURITY__COMPUTE_RELABEL);
94 if ( rv )
95 return rv;
96
97 rv = security_change_sid(arg->ssid, arg->tsid, arg->tclass, &arg->newsid);
98
99 return rv;
100 }
101
flask_security_create(struct xen_flask_transition * arg)102 static int flask_security_create(struct xen_flask_transition *arg)
103 {
104 int rv;
105
106 rv = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
107 if ( rv )
108 return rv;
109
110 rv = security_transition_sid(arg->ssid, arg->tsid, arg->tclass, &arg->newsid);
111
112 return rv;
113 }
114
flask_security_access(struct xen_flask_access * arg)115 static int flask_security_access(struct xen_flask_access *arg)
116 {
117 struct av_decision avd;
118 int rv;
119
120 rv = domain_has_security(current->domain, SECURITY__COMPUTE_AV);
121 if ( rv )
122 return rv;
123
124 rv = security_compute_av(arg->ssid, arg->tsid, arg->tclass, arg->req, &avd);
125 if ( rv < 0 )
126 return rv;
127
128 arg->allowed = avd.allowed;
129 arg->audit_allow = avd.auditallow;
130 arg->audit_deny = avd.auditdeny;
131 arg->seqno = avd.seqno;
132
133 return rv;
134 }
135
flask_security_member(struct xen_flask_transition * arg)136 static int flask_security_member(struct xen_flask_transition *arg)
137 {
138 int rv;
139
140 rv = domain_has_security(current->domain, SECURITY__COMPUTE_MEMBER);
141 if ( rv )
142 return rv;
143
144 rv = security_member_sid(arg->ssid, arg->tsid, arg->tclass, &arg->newsid);
145
146 return rv;
147 }
148
flask_security_setenforce(struct xen_flask_setenforce * arg)149 static int flask_security_setenforce(struct xen_flask_setenforce *arg)
150 {
151 int enforce = !!(arg->enforcing);
152 int rv;
153
154 if ( enforce == flask_enforcing )
155 return 0;
156
157 rv = domain_has_security(current->domain, SECURITY__SETENFORCE);
158 if ( rv )
159 return rv;
160
161 flask_enforcing = enforce;
162
163 if ( flask_enforcing )
164 avc_ss_reset(0);
165
166 return 0;
167 }
168
169 #endif /* COMPAT */
170
flask_security_context(struct xen_flask_sid_context * arg)171 static int flask_security_context(struct xen_flask_sid_context *arg)
172 {
173 int rv;
174 char *buf;
175
176 rv = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
177 if ( rv )
178 return rv;
179
180 buf = safe_copy_string_from_guest(arg->context, arg->size, PAGE_SIZE);
181 if ( IS_ERR(buf) )
182 return PTR_ERR(buf);
183
184 rv = security_context_to_sid(buf, arg->size, &arg->sid);
185 if ( rv < 0 )
186 goto out;
187
188 out:
189 xfree(buf);
190
191 return rv;
192 }
193
flask_security_sid(struct xen_flask_sid_context * arg)194 static int flask_security_sid(struct xen_flask_sid_context *arg)
195 {
196 int rv;
197 char *context;
198 u32 len;
199
200 rv = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
201 if ( rv )
202 return rv;
203
204 rv = security_sid_to_context(arg->sid, &context, &len);
205 if ( rv < 0 )
206 return rv;
207
208 rv = 0;
209
210 if ( len > arg->size )
211 rv = -ERANGE;
212
213 arg->size = len;
214
215 if ( !rv && _copy_to_guest(arg->context, context, len) )
216 rv = -EFAULT;
217
218 xfree(context);
219
220 return rv;
221 }
222
223 #ifndef COMPAT
224
flask_disable(void)225 static int flask_disable(void)
226 {
227 static int flask_disabled = 0;
228
229 if ( ss_initialized )
230 {
231 /* Not permitted after initial policy load. */
232 return -EINVAL;
233 }
234
235 if ( flask_disabled )
236 {
237 /* Only do this once. */
238 return -EINVAL;
239 }
240
241 printk("Flask: Disabled at runtime.\n");
242
243 flask_disabled = 1;
244
245 /* Reset xsm_ops to the original module. */
246 xsm_ops = &dummy_xsm_ops;
247
248 return 0;
249 }
250
flask_security_setavc_threshold(struct xen_flask_setavc_threshold * arg)251 static int flask_security_setavc_threshold(struct xen_flask_setavc_threshold *arg)
252 {
253 int rv = 0;
254
255 if ( arg->threshold != avc_cache_threshold )
256 {
257 rv = domain_has_security(current->domain, SECURITY__SETSECPARAM);
258 if ( rv )
259 goto out;
260 avc_cache_threshold = arg->threshold;
261 }
262
263 out:
264 return rv;
265 }
266
267 #endif /* COMPAT */
268
flask_security_resolve_bool(struct xen_flask_boolean * arg)269 static int flask_security_resolve_bool(struct xen_flask_boolean *arg)
270 {
271 char *name;
272
273 if ( arg->bool_id != -1 )
274 return 0;
275
276 name = safe_copy_string_from_guest(arg->name, arg->size, PAGE_SIZE);
277 if ( IS_ERR(name) )
278 return PTR_ERR(name);
279
280 arg->bool_id = security_find_bool(name);
281 arg->size = 0;
282
283 xfree(name);
284
285 return 0;
286 }
287
flask_security_set_bool(struct xen_flask_boolean * arg)288 static int flask_security_set_bool(struct xen_flask_boolean *arg)
289 {
290 int rv;
291
292 rv = domain_has_security(current->domain, SECURITY__SETBOOL);
293 if ( rv )
294 return rv;
295
296 rv = flask_security_resolve_bool(arg);
297 if ( rv )
298 return rv;
299
300 spin_lock(&sel_sem);
301
302 if ( arg->commit )
303 {
304 int num;
305 int *values;
306
307 rv = security_get_bools(&num, NULL, &values, NULL);
308 if ( rv != 0 )
309 goto out;
310
311 if ( arg->bool_id >= num )
312 {
313 xfree(values);
314 rv = -ENOENT;
315 goto out;
316 }
317 values[arg->bool_id] = !!(arg->new_value);
318
319 arg->enforcing = arg->pending = !!(arg->new_value);
320
321 if ( bool_pending_values )
322 bool_pending_values[arg->bool_id] = !!(arg->new_value);
323
324 rv = security_set_bools(num, values);
325 xfree(values);
326 }
327 else
328 {
329 if ( !bool_pending_values )
330 rv = flask_security_make_bools();
331 if ( !rv && arg->bool_id >= bool_num )
332 rv = -ENOENT;
333 if ( rv )
334 goto out;
335
336 bool_pending_values[arg->bool_id] = !!(arg->new_value);
337 arg->pending = !!(arg->new_value);
338 arg->enforcing = security_get_bool_value(arg->bool_id);
339
340 rv = 0;
341 }
342
343 out:
344 spin_unlock(&sel_sem);
345 return rv;
346 }
347
flask_security_get_bool(struct xen_flask_boolean * arg)348 static int flask_security_get_bool(struct xen_flask_boolean *arg)
349 {
350 int rv;
351
352 rv = flask_security_resolve_bool(arg);
353 if ( rv )
354 return rv;
355
356 spin_lock(&sel_sem);
357
358 rv = security_get_bool_value(arg->bool_id);
359 if ( rv < 0 )
360 goto out;
361
362 arg->enforcing = rv;
363
364 if ( bool_pending_values )
365 arg->pending = bool_pending_values[arg->bool_id];
366 else
367 arg->pending = rv;
368
369 rv = 0;
370
371 if ( arg->size )
372 {
373 char *nameout = security_get_bool_name(arg->bool_id);
374 size_t nameout_len = strlen(nameout);
375 if ( nameout_len > arg->size )
376 rv = -ERANGE;
377 arg->size = nameout_len;
378
379 if ( !rv && _copy_to_guest(arg->name, nameout, nameout_len) )
380 rv = -EFAULT;
381 xfree(nameout);
382 }
383
384 out:
385 spin_unlock(&sel_sem);
386 return rv;
387 }
388
389 #ifndef COMPAT
390
flask_security_commit_bools(void)391 static int flask_security_commit_bools(void)
392 {
393 int rv;
394
395 spin_lock(&sel_sem);
396
397 rv = domain_has_security(current->domain, SECURITY__SETBOOL);
398 if ( rv )
399 goto out;
400
401 if ( bool_pending_values )
402 rv = security_set_bools(bool_num, bool_pending_values);
403
404 out:
405 spin_unlock(&sel_sem);
406 return rv;
407 }
408
flask_security_make_bools(void)409 static int flask_security_make_bools(void)
410 {
411 int ret = 0;
412 int num;
413 int *values = NULL;
414
415 xfree(bool_pending_values);
416
417 ret = security_get_bools(&num, NULL, &values, NULL);
418 if ( ret != 0 )
419 goto out;
420
421 bool_num = num;
422 bool_pending_values = values;
423
424 out:
425 return ret;
426 }
427
428 #ifdef CONFIG_FLASK_AVC_STATS
429
flask_security_avc_cachestats(struct xen_flask_cache_stats * arg)430 static int flask_security_avc_cachestats(struct xen_flask_cache_stats *arg)
431 {
432 struct avc_cache_stats *st;
433
434 if ( arg->cpu >= nr_cpu_ids )
435 return -ENOENT;
436 if ( !cpu_online(arg->cpu) )
437 return -ENOENT;
438
439 st = &per_cpu(avc_cache_stats, arg->cpu);
440
441 arg->lookups = st->lookups;
442 arg->hits = st->hits;
443 arg->misses = st->misses;
444 arg->allocations = st->allocations;
445 arg->reclaims = st->reclaims;
446 arg->frees = st->frees;
447
448 return 0;
449 }
450
451 #endif
452 #endif /* COMPAT */
453
flask_security_load(struct xen_flask_load * load)454 static int flask_security_load(struct xen_flask_load *load)
455 {
456 int ret;
457 void *buf = NULL;
458 bool is_reload = ss_initialized;
459
460 ret = domain_has_security(current->domain, SECURITY__LOAD_POLICY);
461 if ( ret )
462 return ret;
463
464 if ( load->size > MAX_POLICY_SIZE )
465 return -EINVAL;
466
467 buf = xmalloc_bytes(load->size);
468 if ( !buf )
469 return -ENOMEM;
470
471 if ( _copy_from_guest(buf, load->buffer, load->size) )
472 {
473 ret = -EFAULT;
474 goto out_free;
475 }
476
477 spin_lock(&sel_sem);
478
479 ret = security_load_policy(buf, load->size);
480 if ( ret )
481 goto out;
482
483 if ( !is_reload )
484 printk(XENLOG_INFO "Flask: Policy loaded, continuing in %s mode.\n",
485 flask_enforcing ? "enforcing" : "permissive");
486
487 xfree(bool_pending_values);
488 bool_pending_values = NULL;
489 ret = 0;
490
491 out:
492 spin_unlock(&sel_sem);
493 out_free:
494 xfree(buf);
495 return ret;
496 }
497
flask_devicetree_label(struct xen_flask_devicetree_label * arg)498 static int flask_devicetree_label(struct xen_flask_devicetree_label *arg)
499 {
500 int rv;
501 char *buf;
502 u32 sid = arg->sid;
503 u32 perm = sid ? SECURITY__ADD_OCONTEXT : SECURITY__DEL_OCONTEXT;
504
505 rv = domain_has_security(current->domain, perm);
506 if ( rv )
507 return rv;
508
509 buf = safe_copy_string_from_guest(arg->path, arg->length, PAGE_SIZE);
510 if ( IS_ERR(buf) )
511 return PTR_ERR(buf);
512
513 /* buf is consumed or freed by this function */
514 rv = security_devicetree_setlabel(buf, sid);
515
516 return rv;
517 }
518
519 #ifndef COMPAT
520
flask_ocontext_del(struct xen_flask_ocontext * arg)521 static int flask_ocontext_del(struct xen_flask_ocontext *arg)
522 {
523 int rv;
524
525 if ( arg->low > arg->high )
526 return -EINVAL;
527
528 rv = domain_has_security(current->domain, SECURITY__DEL_OCONTEXT);
529 if ( rv )
530 return rv;
531
532 return security_ocontext_del(arg->ocon, arg->low, arg->high);
533 }
534
flask_ocontext_add(struct xen_flask_ocontext * arg)535 static int flask_ocontext_add(struct xen_flask_ocontext *arg)
536 {
537 int rv;
538
539 if ( arg->low > arg->high )
540 return -EINVAL;
541
542 rv = domain_has_security(current->domain, SECURITY__ADD_OCONTEXT);
543 if ( rv )
544 return rv;
545
546 return security_ocontext_add(arg->ocon, arg->low, arg->high, arg->sid);
547 }
548
flask_get_peer_sid(struct xen_flask_peersid * arg)549 static int flask_get_peer_sid(struct xen_flask_peersid *arg)
550 {
551 int rv = -EINVAL;
552 struct domain *d = current->domain;
553 struct domain *peer;
554 struct evtchn *chn;
555 struct domain_security_struct *dsec;
556
557 spin_lock(&d->event_lock);
558
559 if ( !port_is_valid(d, arg->evtchn) )
560 goto out;
561
562 chn = evtchn_from_port(d, arg->evtchn);
563 if ( chn->state != ECS_INTERDOMAIN )
564 goto out;
565
566 peer = chn->u.interdomain.remote_dom;
567 if ( !peer )
568 goto out;
569
570 dsec = peer->ssid;
571 arg->sid = dsec->sid;
572 rv = 0;
573
574 out:
575 spin_unlock(&d->event_lock);
576 return rv;
577 }
578
flask_relabel_domain(struct xen_flask_relabel * arg)579 static int flask_relabel_domain(struct xen_flask_relabel *arg)
580 {
581 int rc;
582 struct domain *d;
583 struct domain_security_struct *csec = current->domain->ssid;
584 struct domain_security_struct *dsec;
585 struct avc_audit_data ad;
586 AVC_AUDIT_DATA_INIT(&ad, NONE);
587
588 d = rcu_lock_domain_by_any_id(arg->domid);
589 if ( d == NULL )
590 return -ESRCH;
591
592 ad.sdom = current->domain;
593 ad.tdom = d;
594 dsec = d->ssid;
595
596 if ( arg->domid == DOMID_SELF )
597 {
598 rc = avc_has_perm(dsec->sid, arg->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELSELF, &ad);
599 if ( rc )
600 goto out;
601 }
602 else
603 {
604 rc = avc_has_perm(csec->sid, dsec->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELFROM, &ad);
605 if ( rc )
606 goto out;
607
608 rc = avc_has_perm(csec->sid, arg->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELTO, &ad);
609 if ( rc )
610 goto out;
611 }
612
613 rc = avc_has_perm(dsec->sid, arg->sid, SECCLASS_DOMAIN, DOMAIN__TRANSITION, &ad);
614 if ( rc )
615 goto out;
616
617 dsec->sid = arg->sid;
618 dsec->self_sid = arg->sid;
619 security_transition_sid(dsec->sid, dsec->sid, SECCLASS_DOMAIN,
620 &dsec->self_sid);
621 if ( d->target )
622 {
623 struct domain_security_struct *tsec = d->target->ssid;
624 security_transition_sid(tsec->sid, dsec->sid, SECCLASS_DOMAIN,
625 &dsec->target_sid);
626 }
627
628 out:
629 rcu_unlock_domain(d);
630 return rc;
631 }
632
633 #endif /* !COMPAT */
634
do_flask_op(XEN_GUEST_HANDLE_PARAM (xsm_op_t)u_flask_op)635 ret_t do_flask_op(XEN_GUEST_HANDLE_PARAM(xsm_op_t) u_flask_op)
636 {
637 xen_flask_op_t op;
638 int rv;
639
640 if ( copy_from_guest(&op, u_flask_op, 1) )
641 return -EFAULT;
642
643 if ( op.interface_version != XEN_FLASK_INTERFACE_VERSION )
644 return -ENOSYS;
645
646 switch ( op.cmd )
647 {
648 case FLASK_LOAD:
649 rv = flask_security_load(&op.u.load);
650 break;
651
652 case FLASK_GETENFORCE:
653 rv = flask_enforcing;
654 break;
655
656 case FLASK_SETENFORCE:
657 rv = flask_security_setenforce(&op.u.enforce);
658 break;
659
660 case FLASK_CONTEXT_TO_SID:
661 rv = flask_security_context(&op.u.sid_context);
662 break;
663
664 case FLASK_SID_TO_CONTEXT:
665 rv = flask_security_sid(&op.u.sid_context);
666 break;
667
668 case FLASK_ACCESS:
669 rv = flask_security_access(&op.u.access);
670 break;
671
672 case FLASK_CREATE:
673 rv = flask_security_create(&op.u.transition);
674 break;
675
676 case FLASK_RELABEL:
677 rv = flask_security_relabel(&op.u.transition);
678 break;
679
680 case FLASK_POLICYVERS:
681 rv = POLICYDB_VERSION_MAX;
682 break;
683
684 case FLASK_GETBOOL:
685 rv = flask_security_get_bool(&op.u.boolean);
686 break;
687
688 case FLASK_SETBOOL:
689 rv = flask_security_set_bool(&op.u.boolean);
690 break;
691
692 case FLASK_COMMITBOOLS:
693 rv = flask_security_commit_bools();
694 break;
695
696 case FLASK_MLS:
697 rv = flask_mls_enabled;
698 break;
699
700 case FLASK_DISABLE:
701 rv = flask_disable();
702 break;
703
704 case FLASK_GETAVC_THRESHOLD:
705 rv = avc_cache_threshold;
706 break;
707
708 case FLASK_SETAVC_THRESHOLD:
709 rv = flask_security_setavc_threshold(&op.u.setavc_threshold);
710 break;
711
712 case FLASK_AVC_HASHSTATS:
713 rv = avc_get_hash_stats(&op.u.hash_stats);
714 break;
715
716 #ifdef CONFIG_FLASK_AVC_STATS
717 case FLASK_AVC_CACHESTATS:
718 rv = flask_security_avc_cachestats(&op.u.cache_stats);
719 break;
720 #endif
721
722 case FLASK_MEMBER:
723 rv = flask_security_member(&op.u.transition);
724 break;
725
726 case FLASK_ADD_OCONTEXT:
727 rv = flask_ocontext_add(&op.u.ocontext);
728 break;
729
730 case FLASK_DEL_OCONTEXT:
731 rv = flask_ocontext_del(&op.u.ocontext);
732 break;
733
734 case FLASK_GET_PEER_SID:
735 rv = flask_get_peer_sid(&op.u.peersid);
736 break;
737
738 case FLASK_RELABEL_DOMAIN:
739 rv = flask_relabel_domain(&op.u.relabel);
740 break;
741
742 case FLASK_DEVICETREE_LABEL:
743 rv = flask_devicetree_label(&op.u.devicetree_label);
744 break;
745
746 default:
747 rv = -ENOSYS;
748 }
749
750 if ( rv < 0 )
751 goto out;
752
753 if ( (FLASK_COPY_OUT&(1UL<<op.cmd)) )
754 {
755 if ( copy_to_guest(u_flask_op, &op, 1) )
756 rv = -EFAULT;
757 }
758
759 out:
760 return rv;
761 }
762
763 #if defined(CONFIG_COMPAT) && !defined(COMPAT)
764 #undef _copy_to_guest
765 #define _copy_to_guest copy_to_compat
766 #undef _copy_from_guest
767 #define _copy_from_guest copy_from_compat
768
769 #include <compat/event_channel.h>
770 #include <compat/xsm/flask_op.h>
771
772 CHECK_flask_access;
773 CHECK_flask_cache_stats;
774 CHECK_flask_hash_stats;
775 CHECK_flask_ocontext;
776 CHECK_flask_peersid;
777 CHECK_flask_relabel;
778 CHECK_flask_setavc_threshold;
779 CHECK_flask_setenforce;
780 CHECK_flask_transition;
781
782 #define COMPAT
783 #define safe_copy_string_from_guest(ch, sz, mx) ({ \
784 XEN_GUEST_HANDLE_PARAM(char) gh; \
785 guest_from_compat_handle(gh, ch); \
786 safe_copy_string_from_guest(gh, sz, mx); \
787 })
788
789 #define xen_flask_load compat_flask_load
790 #define flask_security_load compat_security_load
791
792 #define xen_flask_userlist compat_flask_userlist
793
794 #define xen_flask_sid_context compat_flask_sid_context
795 #define flask_security_context compat_security_context
796 #define flask_security_sid compat_security_sid
797
798 #define xen_flask_boolean compat_flask_boolean
799 #define flask_security_resolve_bool compat_security_resolve_bool
800 #define flask_security_get_bool compat_security_get_bool
801 #define flask_security_set_bool compat_security_set_bool
802
803 #define xen_flask_devicetree_label compat_flask_devicetree_label
804 #define flask_devicetree_label compat_devicetree_label
805
806 #define xen_flask_op_t compat_flask_op_t
807 #undef ret_t
808 #define ret_t int
809 #define do_flask_op compat_flask_op
810
811 #include "flask_op.c"
812 #endif
813