pax_global_header00006660000000000000000000000064122342344070014513gustar00rootroot0000000000000052 comment=674e0683064b3e5c105447a0fd3b185a97208650 checkpolicy-2.2/000077500000000000000000000000001223423440700136535ustar00rootroot00000000000000checkpolicy-2.2/.gitignore000066400000000000000000000000611223423440700156400ustar00rootroot00000000000000checkmodule checkpolicy lex.yy.c y.tab.c y.tab.h checkpolicy-2.2/Android.mk000066400000000000000000000023721223423440700155700ustar00rootroot00000000000000LOCAL_PATH:= $(call my-dir) common_src_files := \ policy_parse.y \ policy_scan.l \ queue.c \ module_compiler.c \ parse_util.c \ policy_define.c common_cflags := \ -Wall -Wshadow -O2 \ -pipe -fno-strict-aliasing \ -Wno-return-type ifeq ($(HOST_OS),darwin) common_cflags += -DDARWIN endif common_includes := \ $(LOCAL_PATH)/ \ $(LOCAL_PATH)/../libsepol/include/ \ $(LOCAL_PATH)/../libsepol/src/ \ ## # "-x c" forces the lex/yacc files to be compiled as c # the build system otherwise forces them to be c++ yacc_flags := -x c ## # checkpolicy # include $(CLEAR_VARS) LOCAL_MODULE := checkpolicy LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) LOCAL_CFLAGS := $(yacc_flags) $(common_cflags) LOCAL_SRC_FILES := $(common_src_files) checkpolicy.c LOCAL_STATIC_LIBRARIES := libsepol LOCAL_YACCFLAGS := -v LOCAL_MODULE_CLASS := EXECUTABLES include $(BUILD_HOST_EXECUTABLE) ## # checkmodule # include $(CLEAR_VARS) LOCAL_MODULE := checkmodule LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) LOCAL_CFLAGS := $(yacc_flags) $(common_cflags) LOCAL_SRC_FILES := $(common_src_files) checkmodule.c LOCAL_STATIC_LIBRARIES := libsepol LOCAL_YACCFLAGS := -v LOCAL_MODULE_CLASS := EXECUTABLES include $(BUILD_HOST_EXECUTABLE) checkpolicy-2.2/COPYING000066400000000000000000000431311223423440700147100ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. checkpolicy-2.2/ChangeLog000066400000000000000000000323551223423440700154350ustar00rootroot000000000000002.2 2013-10-30 * Fix hyphen usage in man pages from Laurent Bigonville. * handle-unknown / -U required argument fix from Laurent Bigonville. * Support overriding Makefile PATH and LIBDIR from Laurent Bigonville. * Support space and : in filenames from Dan Walsh. 2.1.12 2013-02-01 * Fix errors found by coverity * implement default type policy syntax * Free allocated memory when clean up / exit. 2.1.11 2012-09-13 * fd leak reading policy * check return code on ebitmap_set_bit 2.1.10 2012-06-28 * sepolgen: We need to support files that have a + in them * Android/MacOS X build support 2.1.9 2012-03-28 * implement new default labeling behaviors for usr, role, range * Fix dead links to www.nsa.gov/selinux 2.1.8 2011-12-21 * add new helper to translate class sets into bitmaps 2.1.7 2011-12-05 * dis* fixed signed vs unsigned errors * dismod: fix unused parameter errors * test: Makefile: include -W and -Werror * allow ~ in filename transition rules 2.1.6 2011-11-03 * Revert "checkpolicy: Redo filename/filesystem syntax to support filename trans rules" * drop libsepol dynamic link in checkpolicy 2.1.5 2011-09-15 * Separate tunable from boolean during compile. 2.1.4 2011-08-26 * checkpolicy: fix spacing in output message 2.1.3 2011-08-17 * add missing ; to attribute_role_def *Redo filename/filesystem syntax to support filename trans 2.1.2 2011-08-02 * .gitignore changes * dispol output of role trans * man page update: build a module with an older policy version 2.1.1 2011-08-01 * Minor updates to filename trans rule output in dis{mod,pol} 2.1.0 2011-07-27 * Release, minor version bump 2.0.27 2011-07-25 * Add role attribute support by Harry Ciao 2.0.26 2011-05-16 * Wrap file names in filename transitions with quotes by Steve Lawrence. * Allow filesystem names to start with a digit by James Carter. 2.0.25 2011-05-02 * Add support for using the last path compnent in type transitions by Eric Paris. * Allow single digit module versions by Daniel Walsh. * Use better filename identifier for filenames by Daniel Walsh. * Use #defines for dismod selections by Eric Paris. 2.0.24 2011-04-11 * Add new class field in role_transition by Harry Ciao. 2.0.23 2010-12-16 * Remove unused variables to fix compliation under GCC 4.6 by Justin Mattock 2.0.22 2010-06-14 * Update checkmodule man page and usage by Daniel Walsh and Steve Lawrence 2.0.21 2009-11-27 * Add long options to checkpolicy and checkmodule by Guido Trentalancia 2.0.20 2009-10-14 * Add support for building Xen policies from Paul Nuzzi. 2.0.19 2009-02-18 * Fix alias field in module format, caused by boundary format change from Caleb Case. 2.0.18 2008-10-14 * Properly escape regex symbols in the lexer from Stephen Smalley. 2.0.17 2008-10-09 * Add bounds support from KaiGai Kohei. 2.0.16 2008-05-27 * Update checkpolicy for user and role mapping support from Joshua Brindle. 2.0.15 2008-05-05 * Fix for policy module versions that look like IPv4 addresses from Jim Carter. Resolves bug 444451. 2.0.14 2008-03-24 * Add permissive domain support from Eric Paris. 2.0.13 2008-03-05 * Split out non-grammar parts of policy_parse.yacc into policy_define.c and policy_define.h from Todd C. Miller. 2.0.12 2008-03-04 * Initialize struct policy_file before using it, from Todd C. Miller. 2.0.11 2008-03-03 * Remove unused define, move variable out of .y file, simplify COND_ERR, from Todd C. Miller. 2.0.10 2008-02-28 * Use yyerror2() where appropriate from Todd C. Miller. 2.0.9 2008-02-04 * Update dispol for libsepol avtab changes from Stephen Smalley. 2.0.8 2008-01-24 * Deprecate role dominance in parser. 2.0.7 2008-01-02 * Added support for policy capabilities from Todd Miller. 2.0.6 2007-11-15 * Initialize the source file name from the command line argument so that checkpolicy/checkmodule report something more useful than "unknown source". 2.0.5 2007-11-01 * Merged remove use of REJECT and trailing context in lex rules; make ipv4 address parsing like ipv6 from James Carter. 2.0.4 2007-09-18 * Merged handle unknown policydb flag support from Eric Paris. Adds new command line options -U {allow, reject, deny} for selecting the flag when a base module or kernel policy is built. 2.0.3 2007-05-31 * Merged fix for segfault on duplicate require of sensitivity from Caleb Case. * Merged fix for dead URLs in checkpolicy man pages from Dan Walsh. 2.0.2 2007-04-12 * Merged checkmodule man page fix from Dan Walsh. 2.0.1 2007-02-20 * Merged patch to allow dots in class identifiers from Caleb Case. 2.0.0 2007-02-01 * Merged patch to use new libsepol error codes by Karl MacMillan. 1.34.0 2007-01-18 * Updated version for stable branch. 1.33.1 2006-11-13 * Collapse user identifiers and identifiers together. 1.32 2006-10-17 * Updated version for release. 1.30.12 2006-09-28 * Merged user and range_transition support for modules from Darrel Goeddel 1.30.11 2006-09-05 * merged range_transition enhancements and user module format changes from Darrel Goeddel 1.30.10 2006-08-03 * Merged symtab datum patch from Karl MacMillan. 1.30.9 2006-06-29 * Lindent. 1.30.8 2006-06-29 * Merged patch to remove TE rule conflict checking from the parser from Joshua Brindle. This can only be done properly by the expander. 1.30.7 2006-06-27 * Merged patch to make checkpolicy/checkmodule handling of duplicate/conflicting TE rules the same as the expander from Joshua Brindle. 1.30.6 2006-06-26 * Merged optionals in base take 2 patch set from Joshua Brindle. 1.30.5 2006-05-05 * Merged compiler cleanup patch from Karl MacMillan. * Merged fix warnings patch from Karl MacMillan. 1.30.4 2006-04-05 * Changed require_class to reject permissions that have not been declared if building a base module. 1.30.3 2006-03-28 * Fixed checkmodule to call link_modules prior to expand_module to handle optionals. 1.30.2 2006-03-28 * Fixed require_class to avoid shadowing permissions already defined in an inherited common definition. 1.30.1 2006-03-22 * Moved processing of role and user require statements to 2nd pass. 1.30 2006-03-14 * Updated version for release. 1.29.5 2006-03-09 * Fixed bug in role dominance (define_role_dom). 1.29.4 2006-02-14 * Added a check for failure to declare each sensitivity in a level definition. 1.29.3 2006-02-13 * Changed to clone level data for aliased sensitivities to avoid double free upon sens_destroy. Bug reported by Kevin Carr of Tresys Technology. 1.29.2 2006-02-13 * Merged optionals in base patch from Joshua Brindle. 1.29.1 2006-02-01 * Merged sepol_av_to_string patch from Joshua Brindle. 1.28 2005-12-07 * Updated version for release. 1.27.20 2005-12-02 * Merged checkmodule man page from Dan Walsh, and edited it. 1.27.19 2005-12-01 * Added error checking of all ebitmap_set_bit calls for out of memory conditions. 1.27.18 2005-12-01 * Merged removal of compatibility handling of netlink classes (requirement that policies with newer versions include the netlink class definitions, remapping of fine-grained netlink classes in newer source policies to single netlink class when generating older policies) from George Coker. 1.27.17 2005-10-25 * Merged dismod fix from Joshua Brindle. 1.27.16 2005-10-20 * Removed obsolete cond_check_type_rules() function and call and cond_optimize_lists() call from checkpolicy.c; these are handled during parsing and expansion now. 1.27.15 2005-10-19 * Updated calls to expand_module for interface change. 1.27.14 2005-10-19 * Changed checkmodule to verify that expand_module succeeds when building base modules. 1.27.13 2005-10-19 * Merged module compiler fixes from Joshua Brindle. 1.27.12 2005-10-19 * Removed direct calls to hierarchy_check_constraints() and check_assertions() from checkpolicy since they are now called internally by expand_module(). 1.27.11 2005-10-18 * Updated for changes to sepol policydb_index_others interface. 1.27.10 2005-10-17 * Updated for changes to sepol expand_module and link_modules interfaces. 1.27.9 2005-10-13 * Merged support for require blocks inside conditionals from Joshua Brindle (Tresys). 1.27.8 2005-10-06 * Updated for changes to libsepol. 1.27.7 2005-10-05 * Merged several bug fixes from Joshua Brindle (Tresys). 1.27.6 2005-10-03 * Merged MLS in modules patch from Joshua Brindle (Tresys). 1.27.5 2005-09-28 * Merged error handling improvement in checkmodule from Karl MacMillan (Tresys). 1.27.4 2005-09-26 * Merged bugfix for dup role transition error messages from Karl MacMillan (Tresys). 1.27.3 2005-09-23 * Merged policyver/modulever patches from Joshua Brindle (Tresys). 1.27.2 2005-09-20 * Fixed parse_categories handling of undefined category. 1.27.1 2005-09-16 * Merged bug fix for role dominance handling from Darrel Goeddel (TCS). 1.26 2005-09-06 * Updated version for release. 1.25.12 2005-08-22 * Fixed handling of validatetrans constraint expressions. Bug reported by Dan Walsh for checkpolicy -M. 1.25.11 2005-08-18 * Merged use-after-free fix from Serge Hallyn (IBM). Bug found by Coverity. 1.25.10 2005-08-15 * Fixed further memory leaks found by valgrind. 1.25.9 2005-08-15 * Changed checkpolicy to destroy the policydbs prior to exit to allow leak detection. * Fixed several memory leaks found by valgrind. 1.25.8 2005-08-11 * Updated checkpolicy and dispol for the new avtab format. Converted users of ebitmaps to new inline operators. Note: The binary policy format version has been incremented to version 20 as a result of these changes. To build a policy for a kernel that does not yet include these changes, use the -c 19 option to checkpolicy. 1.25.7 2005-08-11 * Merged patch to prohibit use of "self" as a type name from Jason Tang (Tresys). 1.25.6 2005-08-10 * Merged patch to fix dismod compilation from Joshua Brindle (Tresys). 1.25.5 2005-08-09 * Fixed call to hierarchy checking code to pass the right policydb. 1.25.4 2005-08-02 * Merged patch to update dismod for the relocation of the module read/write code from libsemanage to libsepol, and to enable build of test subdirectory from Jason Tang (Tresys). 1.25.3 2005-07-18 * Merged hierarchy check fix from Joshua Brindle (Tresys). 1.25.2 2005-07-06 * Merged loadable module support from Tresys Technology. 1.25.1 2005-06-24 * Merged patch to prohibit the use of * and ~ in type sets (other than in neverallow statements) and in role sets from Joshua Brindle (Tresys). 1.24 2005-06-20 * Updated version for release. 1.23.4 2005-05-19 * Merged cleanup patch from Dan Walsh. 1.23.3 2005-05-13 * Added sepol_ prefix to Flask types to avoid namespace collision with libselinux. 1.23.2 2005-04-29 * Merged identifier fix from Joshua Brindle (Tresys). 1.23.1 2005-04-13 * Merged hierarchical type/role patch from Tresys Technology. * Merged MLS fixes from Darrel Goeddel of TCS. 1.22 2005-03-09 * Updated version for release. 1.21.4 2005-02-17 * Moved genpolusers utility to libsepol. * Merged range_transition support from Darrel Goeddel (TCS). 1.21.3 2005-02-16 * Merged define_user() cleanup patch from Darrel Goeddel (TCS). 1.21.2 2005-02-09 * Changed relabel Makefile target to use restorecon. 1.21.1 2005-01-26 * Merged enhanced MLS support from Darrel Goeddel (TCS). 1.20 2005-01-04 * Merged typeattribute statement patch from Darrel Goeddel of TCS. * Changed genpolusers to handle multiple user config files. * Merged nodecon ordering patch from Chad Hanson of TCS. 1.18 2004-10-07 * MLS build fix. * Fixed Makefile dependencies (Chris PeBenito). * Merged fix for role dominance ordering issue from Chad Hanson of TCS. * Preserve portcon ordering and apply more checking. 1.16 2004-08-13 * Allow empty conditional clauses. * Moved genpolbools utility to libsepol. * Updated for libsepol set functions. * Changed to link with libsepol.a. * Moved core functionality into libsepol. * Merged bug fix for conditional self handling from Karl MacMillan, Dave Caplan, and Joshua Brindle of Tresys. * Added genpolusers program. * Fixed bug in checkpolicy conditional code. 1.14 2004-06-28 * Merged fix for MLS logic from Daniel Thayer of TCS. * Require semicolon terminator for typealias statement. 1.12 2004-06-16 * Merged fine-grained netlink class support. 1.10 2004-04-07 * Merged ipv6 support from James Morris of RedHat. * Fixed compute_av bug discovered by Chad Hanson of TCS. 1.8 2004-03-09 * Merged policydb MLS patch from Chad Hanson of TCS. * Fixed mmap of policy file. 1.6 2004-02-18 * Merged conditional policy extensions from Tresys Technology. * Added typealias declaration support per Russell Coker's request. * Added support for excluding types from type sets based on a patch by David Caplan, but reimplemented as a change to the policy grammar. * Merged patch from Colin Walters to report source file name and line number for errors when available. * Un-deprecated role transitions. 1.4 2003-12-01 * Regenerated headers. * Merged patches from Bastian Blank and Joerg Hoh. 1.2 2003-09-30 * Merged MLS build patch from Karl MacMillan of Tresys. * Merged checkpolicy man page from Magosanyi Arpad. 1.1 2003-08-13 * Fixed endian bug in policydb_write for behavior value. * License -> GPL. * Merged coding style cleanups from James Morris. 1.0 2003-07-11 * Initial public release. checkpolicy-2.2/Makefile000066400000000000000000000026451223423440700153220ustar00rootroot00000000000000# # Makefile for building the checkpolicy program # PREFIX ?= $(DESTDIR)/usr BINDIR ?= $(PREFIX)/bin MANDIR ?= $(PREFIX)/share/man LIBDIR ?= $(PREFIX)/lib INCLUDEDIR ?= $(PREFIX)/include TARGETS = checkpolicy checkmodule YACC = bison -y CFLAGS ?= -g -Wall -Werror -Wshadow -O2 -pipe -fno-strict-aliasing override CFLAGS += -I. -I${INCLUDEDIR} CHECKOBJS = y.tab.o lex.yy.o queue.o module_compiler.o parse_util.o \ policy_define.o CHECKPOLOBJS = $(CHECKOBJS) checkpolicy.o CHECKMODOBJS = $(CHECKOBJS) checkmodule.o LDLIBS=$(LIBDIR)/libsepol.a -lfl GENERATED=lex.yy.c y.tab.c y.tab.h all: $(TARGETS) $(MAKE) -C test checkpolicy: $(CHECKPOLOBJS) checkmodule: $(CHECKMODOBJS) %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< y.tab.o: y.tab.c $(CC) $(filter-out -Werror, $(CFLAGS)) -o $@ -c $< lex.yy.o: lex.yy.c $(CC) $(filter-out -Werror, $(CFLAGS)) -o $@ -c $< y.tab.c: policy_parse.y $(YACC) -d policy_parse.y lex.yy.c: policy_scan.l y.tab.c $(LEX) policy_scan.l install: all -mkdir -p $(BINDIR) -mkdir -p $(MANDIR)/man8 install -m 755 $(TARGETS) $(BINDIR) install -m 644 checkpolicy.8 $(MANDIR)/man8 install -m 644 checkmodule.8 $(MANDIR)/man8 relabel: install /sbin/restorecon $(BINDIR)/checkpolicy /sbin/restorecon $(BINDIR)/checkmodule clean: -rm -f $(TARGETS) $(CHECKPOLOBJS) $(CHECKMODOBJS) y.tab.c y.tab.h lex.yy.c $(MAKE) -C test clean indent: ../scripts/Lindent $(filter-out $(GENERATED),$(wildcard *.[ch])) checkpolicy-2.2/VERSION000066400000000000000000000000041223423440700147150ustar00rootroot000000000000002.2 checkpolicy-2.2/checkmodule.8000066400000000000000000000041531223423440700162320ustar00rootroot00000000000000.TH CHECKMODULE 8 .SH NAME checkmodule \- SELinux policy module compiler .SH SYNOPSIS .B checkmodule .I "[\-h] [\-b] [\-m] [\-M] [\-U handle_unknown ] [\-V] [\-o output_file] [input_file]" .SH "DESCRIPTION" This manual page describes the .BR checkmodule command. .PP .B checkmodule is a program that checks and compiles a SELinux security policy module into a binary representation. It can generate either a base policy module (default) or a non-base policy module (\-m option); typically, you would build a non-base policy module to add to an existing module store that already has a base module provided by the base policy. Use semodule_package to combine this module with its optional file contexts to create a policy package, and then use semodule to install the module package into the module store and load the resulting policy. .SH OPTIONS .TP .B \-b,\-\-binary Read an existing binary policy module file rather than a source policy module file. This option is a development/debugging aid. .TP .B \-h,\-\-help Print usage. .TP .B \-m Generate a non-base policy module. .TP .B \-M,\-\-mls Enable the MLS/MCS support when checking and compiling the policy module. .TP .B \-V,\-\-version Show policy versions created by this program. Note that you cannot currently build older versions. .TP .B \-o,\-\-output filename Write a binary policy module file to the specified filename. Otherwise, checkmodule will only check the syntax of the module source file and will not generate a binary module at all. .TP .B \-U,\-\-handle-unknown Specify how the kernel should handle unknown classes or permissions (deny, allow or reject). .SH EXAMPLE .nf # Build a MLS/MCS-enabled non-base policy module. $ checkmodule \-M \-m httpd.te \-o httpd.mod .fi .SH "SEE ALSO" .B semodule(8), semodule_package(8) SELinux documentation at http://www.nsa.gov/research/selinux, especially "Configuring the SELinux Policy". .SH AUTHOR This manual page was copied from the checkpolicy man page written by Arpad Magosanyi , and edited by Dan Walsh . The program was written by Stephen Smalley . checkpolicy-2.2/checkmodule.c000066400000000000000000000162351223423440700163110ustar00rootroot00000000000000/* * Authors: Joshua Brindle * Karl MacMillan * Jason Tang * * * Copyright (C) 2004-5 Tresys Technology, LLC * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "queue.h" #include "checkpolicy.h" #include "parse_util.h" extern char *optarg; extern int optind; static sidtab_t sidtab; extern int mlspol; static int handle_unknown = SEPOL_DENY_UNKNOWN; static char *txtfile = "policy.conf"; static char *binfile = "policy"; unsigned int policy_type = POLICY_BASE; unsigned int policyvers = MOD_POLICYDB_VERSION_MAX; static int read_binary_policy(policydb_t * p, char *file, char *progname) { int fd; struct stat sb; void *map; struct policy_file f, *fp; fd = open(file, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open '%s': %s\n", file, strerror(errno)); return -1; } if (fstat(fd, &sb) < 0) { fprintf(stderr, "Can't stat '%s': %s\n", file, strerror(errno)); close(fd); return -1; } map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); close(fd); if (map == MAP_FAILED) { fprintf(stderr, "Can't map '%s': %s\n", file, strerror(errno)); return -1; } policy_file_init(&f); f.type = PF_USE_MEMORY; f.data = map; f.len = sb.st_size; fp = &f; if (policydb_init(p)) { fprintf(stderr, "%s: policydb_init: Out of memory!\n", progname); return -1; } if (policydb_read(p, fp, 1)) { fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", progname); return -1; } /* Check Policy Consistency */ if (p->mls) { if (!mlspol) { fprintf(stderr, "%s: MLS policy, but non-MLS" " is specified\n", progname); return -1; } } else { if (mlspol) { fprintf(stderr, "%s: non-MLS policy, but MLS" " is specified\n", progname); return -1; } } return 0; } static int write_binary_policy(policydb_t * p, char *file, char *progname) { FILE *outfp = NULL; struct policy_file pf; int ret; printf("%s: writing binary representation (version %d) to %s\n", progname, policyvers, file); outfp = fopen(file, "w"); if (!outfp) { perror(file); exit(1); } p->policy_type = policy_type; p->policyvers = policyvers; p->handle_unknown = handle_unknown; policy_file_init(&pf); pf.type = PF_USE_STDIO; pf.fp = outfp; ret = policydb_write(p, &pf); if (ret) { fprintf(stderr, "%s: error writing %s\n", progname, file); return -1; } fclose(outfp); return 0; } static void usage(char *progname) { printf("usage: %s [-h] [-V] [-b] [-U handle_unknown] [-m] [-M] [-o FILE] [INPUT]\n", progname); printf("Build base and policy modules.\n"); printf("Options:\n"); printf(" INPUT build module from INPUT (else read from \"%s\")\n", txtfile); printf(" -V show policy versions created by this program\n"); printf(" -b treat input as a binary policy file\n"); printf(" -h print usage\n"); printf(" -U OPTION How to handle unknown classes and permissions\n"); printf(" deny: Deny unknown kernel checks\n"); printf(" reject: Reject loading of policy with unknowns\n"); printf(" allow: Allow unknown kernel checks\n"); printf(" -m build a policy module instead of a base module\n"); printf(" -M enable MLS policy\n"); printf(" -o FILE write module to FILE (else just check syntax)\n"); exit(1); } int main(int argc, char **argv) { char *file = txtfile, *outfile = NULL; unsigned int binary = 0; int ch; int show_version = 0; policydb_t modpolicydb; struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"output", required_argument, NULL, 'o'}, {"binary", no_argument, NULL, 'b'}, {"version", no_argument, NULL, 'V'}, {"handle-unknown", required_argument, NULL, 'U'}, {"mls", no_argument, NULL, 'M'}, {NULL, 0, NULL, 0} }; while ((ch = getopt_long(argc, argv, "ho:bVU:mM", long_options, NULL)) != -1) { switch (ch) { case 'h': usage(argv[0]); break; case 'o': outfile = optarg; break; case 'b': binary = 1; file = binfile; break; case 'V': show_version = 1; break; case 'U': if (!strcasecmp(optarg, "deny")) { handle_unknown = DENY_UNKNOWN; break; } if (!strcasecmp(optarg, "reject")) { handle_unknown = REJECT_UNKNOWN; break; } if (!strcasecmp(optarg, "allow")) { handle_unknown = ALLOW_UNKNOWN; break; } usage(argv[0]); case 'm': policy_type = POLICY_MOD; policyvers = MOD_POLICYDB_VERSION_MAX; break; case 'M': mlspol = 1; break; default: usage(argv[0]); } } if (show_version) { printf("Module versions %d-%d\n", MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX); exit(0); } if (handle_unknown && (policy_type != POLICY_BASE)) { printf("Handling of unknown classes and permissions is only "); printf("valid in the base module\n"); exit(1); } if (optind != argc) { file = argv[optind++]; if (optind != argc) usage(argv[0]); } printf("%s: loading policy configuration from %s\n", argv[0], file); /* Set policydb and sidtab used by libsepol service functions to my structures, so that I can directly populate and manipulate them. */ sepol_set_policydb(&modpolicydb); sepol_set_sidtab(&sidtab); if (binary) { if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) { exit(1); } } else { if (policydb_init(&modpolicydb)) { fprintf(stderr, "%s: out of memory!\n", argv[0]); return -1; } modpolicydb.policy_type = policy_type; modpolicydb.mls = mlspol; modpolicydb.handle_unknown = handle_unknown; if (read_source_policy(&modpolicydb, file, argv[0]) == -1) { exit(1); } if (hierarchy_check_constraints(NULL, &modpolicydb)) { return -1; } } if (modpolicydb.policy_type == POLICY_BASE) { /* Verify that we can successfully expand the base module. */ policydb_t kernpolicydb; if (policydb_init(&kernpolicydb)) { fprintf(stderr, "%s: policydb_init failed\n", argv[0]); exit(1); } if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) { fprintf(stderr, "%s: link modules failed\n", argv[0]); exit(1); } if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) { fprintf(stderr, "%s: expand module failed\n", argv[0]); exit(1); } policydb_destroy(&kernpolicydb); } if (policydb_load_isids(&modpolicydb, &sidtab)) exit(1); sepol_sidtab_destroy(&sidtab); printf("%s: policy configuration loaded\n", argv[0]); if (outfile && write_binary_policy(&modpolicydb, outfile, argv[0]) == -1) { exit(1); } policydb_destroy(&modpolicydb); return 0; } /* FLASK */ checkpolicy-2.2/checkpolicy.8000066400000000000000000000030631223423440700162430ustar00rootroot00000000000000.TH CHECKPOLICY 8 .SH NAME checkpolicy \- SELinux policy compiler .SH SYNOPSIS .B checkpolicy .I "[\-b] [\-d] [\-M] [\-c policyvers] [\-o output_file] [input_file]" .br .SH "DESCRIPTION" This manual page describes the .BR checkpolicy command. .PP .B checkpolicy is a program that checks and compiles a SELinux security policy configuration into a binary representation that can be loaded into the kernel. If no input file name is specified, checkpolicy will attempt to read from policy.conf or policy, depending on whether the \-b flag is specified. .SH OPTIONS .TP .B \-b,\-\-binary Read an existing binary policy file rather than a source policy.conf file. .TP .B \-d,\-\-debug Enter debug mode after loading the policy. .TP .B \-M,\-\-mls Enable the MLS policy when checking and compiling the policy. .TP .B \-o,\-\-output filename Write a binary policy file to the specified filename. .TP .B \-c policyvers Specify the policy version, defaults to the latest. .TP .B \-t,\-\-target Specify the target platform (selinux or xen). .TP .B \-U,\-\-handle-unknown Specify how the kernel should handle unknown classes or permissions (deny, allow or reject). .TP .B \-V,\-\-version Show version information. .TP .B \-h,\-\-help Show usage information. .SH "SEE ALSO" SELinux documentation at http://www.nsa.gov/research/selinux, especially "Configuring the SELinux Policy". .SH AUTHOR This manual page was written by Arpad Magosanyi , and edited by Stephen Smalley . The program was written by Stephen Smalley . checkpolicy-2.2/checkpolicy.c000066400000000000000000000605361223423440700163260ustar00rootroot00000000000000 /* * Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: Karl MacMillan * * Added conditional policy language extensions * * Updated: James Morris * * Added IPv6 support. * * Updated: Joshua Brindle * Karl MacMillan * Jason Tang * * Policy Module support. * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2005 Tresys Technology, LLC * Copyright (C) 2003 Red Hat, Inc., James Morris * 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. */ /* FLASK */ /* * checkpolicy * * Load and check a policy configuration. * * A policy configuration is created in a text format, * and then compiled into a binary format for use by * the security server. By default, checkpolicy reads * the text format. If '-b' is specified, then checkpolicy * reads the binary format instead. * * If '-o output_file' is specified, then checkpolicy * writes the binary format version of the configuration * to the specified output file. * * If '-d' is specified, then checkpolicy permits the user * to interactively test the security server functions with * the loaded policy configuration. * * If '-c' is specified, then the supplied parameter is used to * determine which policy version to use for generating binary * policy. This is for compatibility with older kernels. If any * booleans or conditional rules are thrown away a warning is printed. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DARWIN #include #endif #include #include #include #include #include #include #include #include "queue.h" #include "checkpolicy.h" #include "parse_util.h" extern char *optarg; extern int optind; static policydb_t policydb; static sidtab_t sidtab; extern policydb_t *policydbp; extern int mlspol; static int handle_unknown = SEPOL_DENY_UNKNOWN; static char *txtfile = "policy.conf"; static char *binfile = "policy"; unsigned int policyvers = POLICYDB_VERSION_MAX; void usage(char *progname) { printf ("usage: %s [-b] [-d] [-U handle_unknown (allow,deny,reject)] [-M]" "[-c policyvers (%d-%d)] [-o output_file] [-t target_platform (selinux,xen)]" "[input_file]\n", progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); exit(1); } #define FGETS(out, size, in) \ if (fgets(out,size,in)==NULL) { \ fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,\ strerror(errno)); \ exit(1);\ } static int print_sid(sepol_security_id_t sid, context_struct_t * context __attribute__ ((unused)), void *data __attribute__ ((unused))) { sepol_security_context_t scontext; size_t scontext_len; int rc; rc = sepol_sid_to_context(sid, &scontext, &scontext_len); if (rc) printf("sid %d -> error %d\n", sid, rc); else { printf("sid %d -> scontext %s\n", sid, scontext); free(scontext); } return 0; } struct val_to_name { unsigned int val; char *name; }; static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p) { struct val_to_name *v = p; perm_datum_t *perdatum; perdatum = (perm_datum_t *) datum; if (v->val == perdatum->s.value) { v->name = key; return 1; } return 0; } #ifdef EQUIVTYPES static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d, struct avtab_node *type_rules) { struct avtab_node *p, *c, *n; for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) { /* * Find the insertion point, keeping the list * ordered by source type, then target type, then * target class. */ if (k->source_type < c->key.source_type) break; if (k->source_type == c->key.source_type && k->target_type < c->key.target_type) break; if (k->source_type == c->key.source_type && k->target_type == c->key.target_type && k->target_class < c->key.target_class) break; } /* Insert the rule */ n = malloc(sizeof(struct avtab_node)); if (!n) { fprintf(stderr, "out of memory\n"); exit(1); } n->key = *k; n->datum = *d; n->next = p->next; p->next = n; return 0; } static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args) { struct avtab_node *type_rules = args; if (d->specified & AVTAB_ALLOWED) { /* * Insert the rule into the lists for both * the source type and the target type. */ if (insert_type_rule(k, d, &type_rules[k->source_type - 1])) return -1; if (insert_type_rule(k, d, &type_rules[k->target_type - 1])) return -1; } return 0; } static void free_type_rules(struct avtab_node *l) { struct avtab_node *tmp; while (l) { tmp = l; l = l->next; free(tmp); } } static int identify_equiv_types(void) { struct avtab_node *type_rules, *l1, *l2; int i, j; /* * Create a list of access vector rules for each type * from the access vector table. */ type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim); if (!type_rules) { fprintf(stderr, "out of memory\n"); exit(1); } memset(type_rules, 0, sizeof(struct avtab_node) * policydb.p_types.nprim); if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules)) exit(1); /* * Compare the type lists and identify equivalent types. */ for (i = 0; i < policydb.p_types.nprim - 1; i++) { if (!type_rules[i].next) continue; for (j = i + 1; j < policydb.p_types.nprim; j++) { for (l1 = type_rules[i].next, l2 = type_rules[j].next; l1 && l2; l1 = l1->next, l2 = l2->next) { if (l2->key.source_type == (j + 1)) { if (l1->key.source_type != (i + 1)) break; } else { if (l1->key.source_type != l2->key.source_type) break; } if (l2->key.target_type == (j + 1)) { if (l1->key.target_type != (i + 1)) break; } else { if (l1->key.target_type != l2->key.target_type) break; } if (l1->key.target_class != l2->key.target_class || l1->datum.allowed != l2->datum.allowed) break; } if (l1 || l2) continue; free_type_rules(type_rules[j].next); type_rules[j].next = NULL; printf("Types %s and %s are equivalent.\n", policydb.p_type_val_to_name[i], policydb.p_type_val_to_name[j]); } free_type_rules(type_rules[i].next); type_rules[i].next = NULL; } free(type_rules); return 0; } #endif extern char *av_to_string(uint32_t tclass, sepol_access_vector_t av); int display_bools() { int i; for (i = 0; i < policydbp->p_bools.nprim; i++) { printf("%s : %d\n", policydbp->p_bool_val_to_name[i], policydbp->bool_val_to_struct[i]->state); } return 0; } void display_expr(cond_expr_t * exp) { cond_expr_t *cur; for (cur = exp; cur != NULL; cur = cur->next) { switch (cur->expr_type) { case COND_BOOL: printf("%s ", policydbp->p_bool_val_to_name[cur->bool - 1]); break; case COND_NOT: printf("! "); break; case COND_OR: printf("|| "); break; case COND_AND: printf("&& "); break; case COND_XOR: printf("^ "); break; case COND_EQ: printf("== "); break; case COND_NEQ: printf("!= "); break; default: printf("error!"); break; } } } int display_cond_expressions() { cond_node_t *cur; for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) { printf("expression: "); display_expr(cur->expr); printf("current state: %d\n", cur->cur_state); } return 0; } int change_bool(char *name, int state) { cond_bool_datum_t *bool; bool = hashtab_search(policydbp->p_bools.table, name); if (bool == NULL) { printf("Could not find bool %s\n", name); return -1; } bool->state = state; evaluate_conds(policydbp); return 0; } static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg) { level_datum_t *levdatum = (level_datum_t *) datum; if (!levdatum->isalias && !levdatum->defined) { fprintf(stderr, "Error: sensitivity %s was not used in a level definition!\n", key); return -1; } return 0; } int main(int argc, char **argv) { sepol_security_class_t tclass; sepol_security_id_t ssid, tsid, *sids; sepol_security_context_t scontext; struct sepol_av_decision avd; class_datum_t *cladatum; char ans[80 + 1], *file = txtfile, *outfile = NULL, *path, *fstype; size_t scontext_len, pathlen; unsigned int i; unsigned int protocol, port; unsigned int binary = 0, debug = 0; struct val_to_name v; int ret, ch, fd, target = SEPOL_TARGET_SELINUX; unsigned int nel, uret; struct stat sb; void *map; FILE *outfp = NULL; char *name; int state; int show_version = 0; struct policy_file pf; struct option long_options[] = { {"output", required_argument, NULL, 'o'}, {"target", required_argument, NULL, 't'}, {"binary", no_argument, NULL, 'b'}, {"debug", no_argument, NULL, 'd'}, {"version", no_argument, NULL, 'V'}, {"handle-unknown", required_argument, NULL, 'U'}, {"mls", no_argument, NULL, 'M'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; while ((ch = getopt_long(argc, argv, "o:t:dbU:MVc:h", long_options, NULL)) != -1) { switch (ch) { case 'o': outfile = optarg; break; case 't': if (!strcasecmp(optarg, "Xen")) target = SEPOL_TARGET_XEN; else if (!strcasecmp(optarg, "SELinux")) target = SEPOL_TARGET_SELINUX; else{ fprintf(stderr, "%s: Unknown target platform:" "%s\n", argv[0], optarg); exit(1); } break; case 'b': binary = 1; file = binfile; break; case 'd': debug = 1; break; case 'V': show_version = 1; break; case 'U': if (!strcasecmp(optarg, "deny")) { handle_unknown = DENY_UNKNOWN; break; } if (!strcasecmp(optarg, "allow")) { handle_unknown = ALLOW_UNKNOWN; break; } if (!strcasecmp(optarg, "reject")) { handle_unknown = REJECT_UNKNOWN; break; } usage(argv[0]); case 'M': mlspol = 1; break; case 'c':{ long int n = strtol(optarg, NULL, 10); if (errno) { fprintf(stderr, "Invalid policyvers specified: %s\n", optarg); usage(argv[0]); exit(1); } if (n < POLICYDB_VERSION_MIN || n > POLICYDB_VERSION_MAX) { fprintf(stderr, "policyvers value %ld not in range %d-%d\n", n, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); usage(argv[0]); exit(1); } if (policyvers != n) policyvers = n; break; } case 'h': default: usage(argv[0]); } } if (show_version) { printf("%d (compatibility range %d-%d)\n", policyvers, POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN); exit(0); } if (optind != argc) { file = argv[optind++]; if (optind != argc) usage(argv[0]); } printf("%s: loading policy configuration from %s\n", argv[0], file); /* Set policydb and sidtab used by libsepol service functions to my structures, so that I can directly populate and manipulate them. */ sepol_set_policydb(&policydb); sepol_set_sidtab(&sidtab); if (binary) { fd = open(file, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open '%s': %s\n", file, strerror(errno)); exit(1); } if (fstat(fd, &sb) < 0) { fprintf(stderr, "Can't stat '%s': %s\n", file, strerror(errno)); exit(1); } map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { fprintf(stderr, "Can't map '%s': %s\n", file, strerror(errno)); exit(1); } policy_file_init(&pf); pf.type = PF_USE_MEMORY; pf.data = map; pf.len = sb.st_size; if (policydb_init(&policydb)) { fprintf(stderr, "%s: policydb_init: Out of memory!\n", argv[0]); exit(1); } ret = policydb_read(&policydb, &pf, 1); if (ret) { fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", argv[0]); exit(1); } policydbp = &policydb; /* Check Policy Consistency */ if (policydbp->mls) { if (!mlspol) { fprintf(stderr, "%s: MLS policy, but non-MLS" " is specified\n", argv[0]); exit(1); } } else { if (mlspol) { fprintf(stderr, "%s: non-MLS policy, but MLS" " is specified\n", argv[0]); exit(1); } } } else { policydb_t parse_policy; if (policydb_init(&parse_policy)) exit(1); /* We build this as a base policy first since that is all the parser understands */ parse_policy.policy_type = POLICY_BASE; policydb_set_target_platform(&parse_policy, target); /* Let sepol know if we are dealing with MLS support */ parse_policy.mls = mlspol; parse_policy.handle_unknown = handle_unknown; policydbp = &parse_policy; if (read_source_policy(policydbp, file, "checkpolicy") < 0) exit(1); if (hashtab_map(policydbp->p_levels.table, check_level, NULL)) exit(1); if (policydb_init(&policydb)) { fprintf(stderr, "%s: policydb_init failed\n", argv[0]); exit(1); } /* Linking takes care of optional avrule blocks */ if (link_modules(NULL, &parse_policy, NULL, 0, 0)) { fprintf(stderr, "Error while resolving optionals\n"); exit(1); } if (expand_module(NULL, &parse_policy, &policydb, 0, 1)) { fprintf(stderr, "Error while expanding policy\n"); exit(1); } policydb_destroy(&parse_policy); policydbp = &policydb; } if (policydb_load_isids(&policydb, &sidtab)) exit(1); printf("%s: policy configuration loaded\n", argv[0]); if (outfile) { printf ("%s: writing binary representation (version %d) to %s\n", argv[0], policyvers, outfile); outfp = fopen(outfile, "w"); if (!outfp) { perror(outfile); exit(1); } policydb.policy_type = POLICY_KERN; policydb.policyvers = policyvers; policy_file_init(&pf); pf.type = PF_USE_STDIO; pf.fp = outfp; ret = policydb_write(&policydb, &pf); if (ret) { fprintf(stderr, "%s: error writing %s\n", argv[0], outfile); exit(1); } fclose(outfp); } if (!debug) { policydb_destroy(&policydb); exit(0); } menu: printf("\nSelect an option:\n"); printf("0) Call compute_access_vector\n"); printf("1) Call sid_to_context\n"); printf("2) Call context_to_sid\n"); printf("3) Call transition_sid\n"); printf("4) Call member_sid\n"); printf("5) Call change_sid\n"); printf("6) Call list_sids\n"); printf("7) Call load_policy\n"); printf("8) Call fs_sid\n"); printf("9) Call port_sid\n"); printf("a) Call netif_sid\n"); printf("b) Call node_sid\n"); printf("c) Call fs_use\n"); printf("d) Call genfs_sid\n"); printf("e) Call get_user_sids\n"); printf("f) display conditional bools\n"); printf("g) display conditional expressions\n"); printf("h) change a boolean value\n"); #ifdef EQUIVTYPES printf("z) Show equivalent types\n"); #endif printf("m) Show menu again\n"); printf("q) Exit\n"); while (1) { printf("\nChoose: "); FGETS(ans, sizeof(ans), stdin); switch (ans[0]) { case '0': printf("source sid? "); FGETS(ans, sizeof(ans), stdin); ssid = atoi(ans); printf("target sid? "); FGETS(ans, sizeof(ans), stdin); tsid = atoi(ans); printf("target class? "); FGETS(ans, sizeof(ans), stdin); if (isdigit(ans[0])) { tclass = atoi(ans); if (!tclass || tclass > policydb.p_classes.nprim) { printf("\nNo such class.\n"); break; } cladatum = policydb.class_val_to_struct[tclass - 1]; } else { ans[strlen(ans) - 1] = 0; cladatum = (class_datum_t *) hashtab_search(policydb. p_classes. table, ans); if (!cladatum) { printf("\nNo such class\n"); break; } tclass = cladatum->s.value; } if (!cladatum->comdatum && !cladatum->permissions.nprim) { printf ("\nNo access vector definition for that class\n"); break; } ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd); switch (ret) { case 0: printf("\nallowed {"); for (i = 1; i <= sizeof(avd.allowed) * 8; i++) { if (avd.allowed & (1 << (i - 1))) { v.val = i; ret = hashtab_map(cladatum-> permissions. table, find_perm, &v); if (!ret && cladatum->comdatum) { ret = hashtab_map (cladatum-> comdatum-> permissions.table, find_perm, &v); } if (ret) printf(" %s", v.name); } } printf(" }\n"); break; case -EINVAL: printf("\ninvalid sid\n"); break; default: printf("return code 0x%x\n", ret); } break; case '1': printf("sid? "); FGETS(ans, sizeof(ans), stdin); ssid = atoi(ans); ret = sepol_sid_to_context(ssid, &scontext, &scontext_len); switch (ret) { case 0: printf("\nscontext %s\n", scontext); free(scontext); break; case -EINVAL: printf("\ninvalid sid\n"); break; case -ENOMEM: printf("\nout of memory\n"); break; default: printf("return code 0x%x\n", ret); } break; case '2': printf("scontext? "); FGETS(ans, sizeof(ans), stdin); scontext_len = strlen(ans); ans[scontext_len - 1] = 0; ret = sepol_context_to_sid(ans, scontext_len, &ssid); switch (ret) { case 0: printf("\nsid %d\n", ssid); break; case -EINVAL: printf("\ninvalid context\n"); break; case -ENOMEM: printf("\nout of memory\n"); break; default: printf("return code 0x%x\n", ret); } break; case '3': case '4': case '5': ch = ans[0]; printf("source sid? "); FGETS(ans, sizeof(ans), stdin); ssid = atoi(ans); printf("target sid? "); FGETS(ans, sizeof(ans), stdin); tsid = atoi(ans); printf("object class? "); FGETS(ans, sizeof(ans), stdin); if (isdigit(ans[0])) { tclass = atoi(ans); if (!tclass || tclass > policydb.p_classes.nprim) { printf("\nNo such class.\n"); break; } } else { ans[strlen(ans) - 1] = 0; cladatum = (class_datum_t *) hashtab_search(policydb. p_classes. table, ans); if (!cladatum) { printf("\nNo such class\n"); break; } tclass = cladatum->s.value; } if (ch == '3') ret = sepol_transition_sid(ssid, tsid, tclass, &ssid); else if (ch == '4') ret = sepol_member_sid(ssid, tsid, tclass, &ssid); else ret = sepol_change_sid(ssid, tsid, tclass, &ssid); switch (ret) { case 0: printf("\nsid %d\n", ssid); break; case -EINVAL: printf("\ninvalid sid\n"); break; case -ENOMEM: printf("\nout of memory\n"); break; default: printf("return code 0x%x\n", ret); } break; case '6': sepol_sidtab_map(&sidtab, print_sid, 0); break; case '7': printf("pathname? "); FGETS(ans, sizeof(ans), stdin); pathlen = strlen(ans); ans[pathlen - 1] = 0; printf("%s: loading policy configuration from %s\n", argv[0], ans); fd = open(ans, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open '%s': %s\n", ans, strerror(errno)); break; } if (fstat(fd, &sb) < 0) { fprintf(stderr, "Can't stat '%s': %s\n", ans, strerror(errno)); break; } map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { fprintf(stderr, "Can't map '%s': %s\n", ans, strerror(errno)); break; } ret = sepol_load_policy(map, sb.st_size); switch (ret) { case 0: printf("\nsuccess\n"); break; case -EINVAL: printf("\ninvalid policy\n"); break; case -ENOMEM: printf("\nout of memory\n"); break; default: printf("return code 0x%x\n", ret); } break; case '8': printf("fs kdevname? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; sepol_fs_sid(ans, &ssid, &tsid); printf("fs_sid %d default_file_sid %d\n", ssid, tsid); break; case '9': printf("protocol? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP")) protocol = IPPROTO_TCP; else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP")) protocol = IPPROTO_UDP; else { printf("unknown protocol\n"); break; } printf("port? "); FGETS(ans, sizeof(ans), stdin); port = atoi(ans); sepol_port_sid(0, 0, protocol, port, &ssid); printf("sid %d\n", ssid); break; case 'a': printf("netif name? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; sepol_netif_sid(ans, &ssid, &tsid); printf("if_sid %d default_msg_sid %d\n", ssid, tsid); break; case 'b':{ char *p; int family, len; struct in_addr addr4; struct in6_addr addr6; printf("protocol family? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; if (!strcasecmp(ans, "ipv4")) family = AF_INET; else if (!strcasecmp(ans, "ipv6")) family = AF_INET6; else { printf("unknown protocol family\n"); break; } printf("node address? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; if (family == AF_INET) { p = (char *)&addr4; len = sizeof(addr4); } else { p = (char *)&addr6; len = sizeof(addr6); } if (inet_pton(family, ans, p) < 1) { printf("error parsing address\n"); break; } sepol_node_sid(family, p, len, &ssid); printf("sid %d\n", ssid); break; } case 'c': printf("fstype? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; sepol_fs_use(ans, &uret, &ssid); switch (uret) { case SECURITY_FS_USE_XATTR: printf("use xattr\n"); break; case SECURITY_FS_USE_TRANS: printf("use transition SIDs\n"); break; case SECURITY_FS_USE_TASK: printf("use task SIDs\n"); break; case SECURITY_FS_USE_GENFS: printf("use genfs\n"); break; case SECURITY_FS_USE_NONE: printf("no labeling support\n"); break; } printf("sid %d\n", ssid); break; case 'd': printf("fstype? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; fstype = strdup(ans); printf("path? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; path = strdup(ans); printf("object class? "); FGETS(ans, sizeof(ans), stdin); if (isdigit(ans[0])) { tclass = atoi(ans); if (!tclass || tclass > policydb.p_classes.nprim) { printf("\nNo such class.\n"); break; } } else { ans[strlen(ans) - 1] = 0; cladatum = (class_datum_t *) hashtab_search(policydb. p_classes. table, ans); if (!cladatum) { printf("\nNo such class\n"); break; } tclass = cladatum->s.value; } sepol_genfs_sid(fstype, path, tclass, &ssid); printf("sid %d\n", ssid); free(fstype); free(path); break; case 'e': printf("from SID? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; ssid = atoi(ans); printf("username? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; ret = sepol_get_user_sids(ssid, ans, &sids, &nel); switch (ret) { case 0: if (!nel) printf("\nnone\n"); for (i = 0; i < nel; i++) print_sid(sids[i], NULL, NULL); free(sids); break; case -ENOMEM: printf("\nout of memory\n"); break; case -EINVAL: printf("\ninvalid argument\n"); break; default: printf("\nerror\n"); break; } break; case 'f': display_bools(); break; case 'g': display_cond_expressions(); break; case 'h': printf("name? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; name = malloc((strlen(ans) + 1) * sizeof(char)); if (name == NULL) { fprintf(stderr, "couldn't malloc string.\n"); break; } strcpy(name, ans); printf("state? "); FGETS(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; if (atoi(ans)) state = 1; else state = 0; change_bool(name, state); free(name); break; #ifdef EQUIVTYPES case 'z': identify_equiv_types(); break; #endif case 'm': goto menu; case 'q': exit(0); break; default: printf("\nUnknown option %s.\n", ans); } } return 0; } /* FLASK */ checkpolicy-2.2/checkpolicy.h000066400000000000000000000005271223423440700163250ustar00rootroot00000000000000#ifndef _CHECKPOLICY_H_ #define _CHECKPOLICY_H_ #include typedef struct te_assert { ebitmap_t stypes; ebitmap_t ttypes; ebitmap_t tclasses; int self; sepol_access_vector_t *avp; unsigned long line; struct te_assert *next; } te_assert_t; te_assert_t *te_assertions; extern unsigned int policyvers; #endif checkpolicy-2.2/module_compiler.c000066400000000000000000001131501223423440700171770ustar00rootroot00000000000000/* Author : Joshua Brindle * Karl MacMillan * Jason Tang * Added support for binary policy modules * * Copyright (C) 2004 - 2005 Tresys Technology, LLC * 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. */ #include #include #include #include #include #include #include #include "queue.h" #include "module_compiler.h" union stack_item_u { avrule_block_t *avrule; cond_list_t *cond_list; }; typedef struct scope_stack { union stack_item_u u; int type; /* for above union: 1 = avrule block, 2 = conditional */ avrule_decl_t *decl; /* if in an avrule block, which * declaration is current */ avrule_t *last_avrule; int in_else; /* if in an avrule block, within ELSE branch */ int require_given; /* 1 if this block had at least one require */ struct scope_stack *parent, *child; } scope_stack_t; extern policydb_t *policydbp; extern queue_t id_queue; extern int yyerror(char *msg); extern void yyerror2(char *fmt, ...); static int push_stack(int stack_type, ...); static void pop_stack(void); /* keep track of the last item added to the stack */ static scope_stack_t *stack_top = NULL; static avrule_block_t *last_block; static uint32_t next_decl_id = 1; int define_policy(int pass, int module_header_given) { char *id; if (module_header_given) { if (policydbp->policy_type != POLICY_MOD) { yyerror ("Module specification found while not building a policy module.\n"); return -1; } if (pass == 2) { while ((id = queue_remove(id_queue)) != NULL) free(id); } else { id = (char *)queue_remove(id_queue); if (!id) { yyerror("no module name"); return -1; } policydbp->name = id; if ((policydbp->version = queue_remove(id_queue)) == NULL) { yyerror ("Expected a module version but none was found."); return -1; } } } else { if (policydbp->policy_type == POLICY_MOD) { yyerror ("Building a policy module, but no module specification found.\n"); return -1; } } /* the first declaration within the global avrule block will always have an id of 1 */ next_decl_id = 2; /* reset the scoping stack */ while (stack_top != NULL) { pop_stack(); } if (push_stack(1, policydbp->global, policydbp->global->branch_list) == -1) { return -1; } last_block = policydbp->global; return 0; } /* Given the current parse stack, returns 1 if a declaration would be * allowed here or 0 if not. For example, declarations are not * allowed in conditionals, so if there are any conditionals in the * current scope stack then this would return a 0. */ static int is_declaration_allowed(void) { if (stack_top->type != 1 || stack_top->in_else) { return 0; } return 1; } /* Attempt to declare a symbol within the current declaration. If * currently within a non-conditional and in a non-else branch then * insert the symbol, return 0 on success if symbol was undeclared. * For roles and users, it is legal to have multiple declarations; as * such return 1 to indicate that caller must free() the datum because * it was not added. If symbols may not be declared here return -1. * For duplicate declarations return -2. For all else, including out * of memory, return -3. Note that dest_value and datum_value might * not be restricted pointers. */ int declare_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value) { avrule_decl_t *decl = stack_top->decl; int retval; /* first check that symbols may be declared here */ if (!is_declaration_allowed()) { return -1; } retval = symtab_insert(policydbp, symbol_type, key, datum, SCOPE_DECL, decl->decl_id, dest_value); if (retval == 1 && dest_value) { symtab_datum_t *s = (symtab_datum_t *) hashtab_search(policydbp-> symtab[symbol_type].table, key); assert(s != NULL); if (symbol_type == SYM_LEVELS) { *dest_value = ((level_datum_t *)s)->level->sens; } else { *dest_value = s->value; } } else if (retval == -2) { return -2; } else if (retval < 0) { return -3; } else { /* fall through possible if retval is 0 */ } if (datum_value != NULL) { if (ebitmap_set_bit(decl->declared.scope + symbol_type, *datum_value - 1, 1)) { return -3; } } return retval; } static int role_implicit_bounds(hashtab_t roles_tab, char *role_id, role_datum_t *role) { role_datum_t *bounds; char *bounds_id, *delim; delim = strrchr(role_id, '.'); if (!delim) return 0; /* no implicit boundary */ bounds_id = strdup(role_id); if (!bounds_id) { yyerror("out of memory"); return -1; } bounds_id[(size_t)(delim - role_id)] = '\0'; bounds = hashtab_search(roles_tab, bounds_id); if (!bounds) { yyerror2("role %s doesn't exist, is implicit bounds of %s", bounds_id, role_id); return -1; } if (!role->bounds) role->bounds = bounds->s.value; else if (role->bounds != bounds->s.value) { yyerror2("role %s has inconsistent bounds %s/%s", role_id, bounds_id, policydbp->p_role_val_to_name[role->bounds - 1]); return -1; } free(bounds_id); return 0; } role_datum_t *declare_role(unsigned char isattr) { char *id = queue_remove(id_queue), *dest_id = NULL; role_datum_t *role = NULL, *dest_role = NULL; int retval; uint32_t value; if (id == NULL) { yyerror("no role name"); return NULL; } if ((role = (role_datum_t *) malloc(sizeof(*role))) == NULL) { yyerror("Out of memory!"); free(id); return NULL; } role_datum_init(role); role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE; retval = declare_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &value, &value); if (retval == 0) { role->s.value = value; if ((dest_id = strdup(id)) == NULL) { yyerror("Out of memory!"); return NULL; } } else { /* this role was already declared in this module, or error */ dest_id = id; role_datum_destroy(role); free(role); } if (retval == 0 || retval == 1) { /* create a new role_datum_t for this decl, if necessary */ hashtab_t roles_tab; assert(stack_top->type == 1); if (stack_top->parent == NULL) { /* in parent, so use global symbol table */ roles_tab = policydbp->p_roles.table; } else { roles_tab = stack_top->decl->p_roles.table; } dest_role = (role_datum_t *) hashtab_search(roles_tab, dest_id); if (dest_role == NULL) { if ((dest_role = (role_datum_t *) malloc(sizeof(*dest_role))) == NULL) { yyerror("Out of memory!"); free(dest_id); return NULL; } role_datum_init(dest_role); dest_role->s.value = value; dest_role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE; if (role_implicit_bounds(roles_tab, dest_id, dest_role)) { free(dest_id); role_datum_destroy(dest_role); free(dest_role); return NULL; } if (hashtab_insert(roles_tab, dest_id, dest_role)) { yyerror("Out of memory!"); free(dest_id); role_datum_destroy(dest_role); free(dest_role); return NULL; } } else { free(dest_id); } } else { free(dest_id); } switch (retval) { case -3:{ yyerror("Out of memory!"); return NULL; } case -2:{ yyerror("duplicate declaration of role"); return NULL; } case -1:{ yyerror("could not declare role here"); return NULL; } case 0:{ if (ebitmap_set_bit (&dest_role->dominates, role->s.value - 1, 1)) { yyerror("out of memory"); return NULL; } return dest_role; } case 1:{ return dest_role; /* role already declared for this block */ } default:{ assert(0); /* should never get here */ } } } type_datum_t *declare_type(unsigned char primary, unsigned char isattr) { char *id; type_datum_t *typdatum; int retval; uint32_t value = 0; id = (char *)queue_remove(id_queue); if (!id) { yyerror("no type/attribute name?"); return NULL; } if (strcmp(id, "self") == 0) { yyerror ("'self' is a reserved type name and may not be declared."); free(id); return NULL; } typdatum = (type_datum_t *) malloc(sizeof(type_datum_t)); if (!typdatum) { yyerror("Out of memory!"); free(id); return NULL; } type_datum_init(typdatum); typdatum->primary = primary; typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE; retval = declare_symbol(SYM_TYPES, id, typdatum, &value, &value); if (retval == 0 || retval == 1) { if (typdatum->primary) { typdatum->s.value = value; } } else { /* error occurred (can't have duplicate type declarations) */ free(id); type_datum_destroy(typdatum); free(typdatum); } switch (retval) { case -3:{ yyerror("Out of memory!"); return NULL; } case -2:{ yyerror2("duplicate declaration of type/attribute"); return NULL; } case -1:{ yyerror("could not declare type/attribute here"); return NULL; } case 0: case 1:{ return typdatum; } default:{ assert(0); /* should never get here */ } } } static int user_implicit_bounds(hashtab_t users_tab, char *user_id, user_datum_t *user) { user_datum_t *bounds; char *bounds_id, *delim; delim = strrchr(user_id, '.'); if (!delim) return 0; /* no implicit boundary */ bounds_id = strdup(user_id); if (!bounds_id) { yyerror("out of memory"); return -1; } bounds_id[(size_t)(delim - user_id)] = '\0'; bounds = hashtab_search(users_tab, bounds_id); if (!bounds) { yyerror2("user %s doesn't exist, is implicit bounds of %s", bounds_id, user_id); return -1; } if (!user->bounds) user->bounds = bounds->s.value; else if (user->bounds != bounds->s.value) { yyerror2("user %s has inconsistent bounds %s/%s", user_id, bounds_id, policydbp->p_role_val_to_name[user->bounds - 1]); return -1; } free(bounds_id); return 0; } user_datum_t *declare_user(void) { char *id = queue_remove(id_queue), *dest_id = NULL; user_datum_t *user = NULL, *dest_user = NULL; int retval; uint32_t value = 0; if (id == NULL) { yyerror("no user name"); return NULL; } if ((user = (user_datum_t *) malloc(sizeof(*user))) == NULL) { yyerror("Out of memory!"); free(id); return NULL; } user_datum_init(user); retval = declare_symbol(SYM_USERS, id, (hashtab_datum_t *) user, &value, &value); if (retval == 0) { user->s.value = value; if ((dest_id = strdup(id)) == NULL) { yyerror("Out of memory!"); return NULL; } } else { /* this user was already declared in this module, or error */ dest_id = id; user_datum_destroy(user); free(user); } if (retval == 0 || retval == 1) { /* create a new user_datum_t for this decl, if necessary */ hashtab_t users_tab; assert(stack_top->type == 1); if (stack_top->parent == NULL) { /* in parent, so use global symbol table */ users_tab = policydbp->p_users.table; } else { users_tab = stack_top->decl->p_users.table; } dest_user = (user_datum_t *) hashtab_search(users_tab, dest_id); if (dest_user == NULL) { if ((dest_user = (user_datum_t *) malloc(sizeof(*dest_user))) == NULL) { yyerror("Out of memory!"); free(dest_id); return NULL; } user_datum_init(dest_user); dest_user->s.value = value; if (user_implicit_bounds(users_tab, dest_id, dest_user)) { free(dest_id); user_datum_destroy(dest_user); free(dest_user); return NULL; } if (hashtab_insert(users_tab, dest_id, dest_user)) { yyerror("Out of memory!"); free(dest_id); user_datum_destroy(dest_user); free(dest_user); return NULL; } } else { free(dest_id); } } else { free(dest_id); } switch (retval) { case -3:{ yyerror("Out of memory!"); return NULL; } case -2:{ yyerror("duplicate declaration of user"); return NULL; } case -1:{ yyerror("could not declare user here"); return NULL; } case 0:{ return dest_user; } case 1:{ return dest_user; /* user already declared for this block */ } default:{ assert(0); /* should never get here */ } } } /* Return a type_datum_t for the local avrule_decl with the given ID. * If it does not exist, create one with the same value as 'value'. * This function assumes that the ID is within scope. c.f., * is_id_in_scope(). * * NOTE: this function usurps ownership of id afterwards. The caller * shall not reference it nor free() it afterwards. */ type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr) { type_datum_t *dest_typdatum; hashtab_t types_tab; assert(stack_top->type == 1); if (stack_top->parent == NULL) { /* in global, so use global symbol table */ types_tab = policydbp->p_types.table; } else { types_tab = stack_top->decl->p_types.table; } dest_typdatum = hashtab_search(types_tab, id); if (!dest_typdatum) { dest_typdatum = (type_datum_t *) malloc(sizeof(type_datum_t)); if (dest_typdatum == NULL) { free(id); return NULL; } type_datum_init(dest_typdatum); dest_typdatum->s.value = value; dest_typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE; dest_typdatum->primary = 1; if (hashtab_insert(types_tab, id, dest_typdatum)) { free(id); type_datum_destroy(dest_typdatum); free(dest_typdatum); return NULL; } } else { free(id); if (dest_typdatum->flavor != isattr ? TYPE_ATTRIB : TYPE_TYPE) { return NULL; } } return dest_typdatum; } /* Return a role_datum_t for the local avrule_decl with the given ID. * If it does not exist, create one with the same value as 'value'. * This function assumes that the ID is within scope. c.f., * is_id_in_scope(). * * NOTE: this function usurps ownership of id afterwards. The caller * shall not reference it nor free() it afterwards. */ role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr) { role_datum_t *dest_roledatum; hashtab_t roles_tab; assert(stack_top->type == 1); if (stack_top->parent == NULL) { /* in global, so use global symbol table */ roles_tab = policydbp->p_roles.table; } else { roles_tab = stack_top->decl->p_roles.table; } dest_roledatum = hashtab_search(roles_tab, id); if (!dest_roledatum) { dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t)); if (dest_roledatum == NULL) { free(id); return NULL; } role_datum_init(dest_roledatum); dest_roledatum->s.value = value; dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE; if (hashtab_insert(roles_tab, id, dest_roledatum)) { free(id); role_datum_destroy(dest_roledatum); free(dest_roledatum); return NULL; } } else { free(id); if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE) return NULL; } return dest_roledatum; } /* Given the current parse stack, returns 1 if a requirement would be * allowed here or 0 if not. For example, the ELSE branch may never * have its own requirements. */ static int is_require_allowed(void) { if (stack_top->type == 1 && !stack_top->in_else) { return 1; } return 0; } /* Attempt to require a symbol within the current scope. If currently * within an optional (and not its else branch), add the symbol to the * required list. Return 0 on success, 1 if caller needs to free() * datum. If symbols may not be declared here return -1. For duplicate * declarations return -2. For all else, including out of memory, * return -3.. Note that dest_value and datum_value might not be * restricted pointers. */ int require_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value) { avrule_decl_t *decl = stack_top->decl; int retval; /* first check that symbols may be required here */ if (!is_require_allowed()) { return -1; } retval = symtab_insert(policydbp, symbol_type, key, datum, SCOPE_REQ, decl->decl_id, dest_value); if (retval == 1) { symtab_datum_t *s = (symtab_datum_t *) hashtab_search(policydbp-> symtab[symbol_type].table, key); assert(s != NULL); if (symbol_type == SYM_LEVELS) { *dest_value = ((level_datum_t *)s)->level->sens; } else { *dest_value = s->value; } } else if (retval == -2) { /* ignore require statements if that symbol was * previously declared and is in current scope */ int prev_declaration_ok = 0; if (is_id_in_scope(symbol_type, key)) { if (symbol_type == SYM_TYPES) { /* check that previous symbol has same * type/attribute-ness */ unsigned char new_isattr = ((type_datum_t *) datum)->flavor; type_datum_t *old_datum = (type_datum_t *) hashtab_search(policydbp-> symtab [SYM_TYPES]. table, key); assert(old_datum != NULL); unsigned char old_isattr = old_datum->flavor; prev_declaration_ok = (old_isattr == new_isattr ? 1 : 0); } else { prev_declaration_ok = 1; } } if (prev_declaration_ok) { /* ignore this require statement because it * was already declared within my scope */ stack_top->require_given = 1; return 1; } else { /* previous declaration was not in scope or * had a mismatched type/attribute, so * generate an error */ return -2; } } else if (retval < 0) { return -3; } else { /* fall through possible if retval is 0 or 1 */ } if (datum_value != NULL) { if (ebitmap_set_bit(decl->required.scope + symbol_type, *datum_value - 1, 1)) { return -3; } } stack_top->require_given = 1; return retval; } int add_perm_to_class(uint32_t perm_value, uint32_t class_value) { avrule_decl_t *decl = stack_top->decl; scope_index_t *scope; assert(perm_value >= 1); assert(class_value >= 1); scope = &decl->required; if (class_value > scope->class_perms_len) { int i; ebitmap_t *new_map = realloc(scope->class_perms_map, class_value * sizeof(*new_map)); if (new_map == NULL) { return -1; } scope->class_perms_map = new_map; for (i = scope->class_perms_len; i < class_value; i++) { ebitmap_init(scope->class_perms_map + i); } scope->class_perms_len = class_value; } if (ebitmap_set_bit(scope->class_perms_map + class_value - 1, perm_value - 1, 1)) { return -1; } return 0; } static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { if (key) free(key); free(datum); return 0; } static void class_datum_destroy(class_datum_t * cladatum) { if (cladatum != NULL) { hashtab_map(cladatum->permissions.table, perm_destroy, NULL); hashtab_destroy(cladatum->permissions.table); free(cladatum); } } int require_class(int pass) { char *class_id = queue_remove(id_queue); char *perm_id = NULL; class_datum_t *datum = NULL; perm_datum_t *perm = NULL; int ret; if (pass == 2) { free(class_id); while ((perm_id = queue_remove(id_queue)) != NULL) free(perm_id); return 0; } /* first add the class if it is not already there */ if (class_id == NULL) { yyerror("no class name for class definition?"); return -1; } if ((datum = calloc(1, sizeof(*datum))) == NULL || symtab_init(&datum->permissions, PERM_SYMTAB_SIZE)) { yyerror("Out of memory!"); goto cleanup; } ret = require_symbol(SYM_CLASSES, class_id, datum, &datum->s.value, &datum->s.value); switch (ret) { case -3:{ yyerror("Out of memory!"); free(class_id); class_datum_destroy(datum); goto cleanup; } case -2:{ yyerror("duplicate declaration of class"); free(class_id); class_datum_destroy(datum); goto cleanup; } case -1:{ yyerror("could not require class here"); free(class_id); class_datum_destroy(datum); goto cleanup; } case 0:{ /* a new class was added; reindex everything */ if (policydb_index_classes(policydbp)) { yyerror("Out of memory!"); goto cleanup; } break; } case 1:{ class_datum_destroy(datum); datum = hashtab_search(policydbp->p_classes.table, class_id); assert(datum); /* the class datum should have existed */ free(class_id); break; } default:{ assert(0); /* should never get here */ } } /* now add each of the permissions to this class's requirements */ while ((perm_id = queue_remove(id_queue)) != NULL) { int allocated = 0; /* Is the permission already in the table? */ perm = hashtab_search(datum->permissions.table, perm_id); if (!perm && datum->comdatum) perm = hashtab_search(datum->comdatum->permissions.table, perm_id); if (perm) { /* Yes, drop the name. */ free(perm_id); } else { /* No - allocate and insert an entry for it. */ if (policydbp->policy_type == POLICY_BASE) { yyerror2 ("Base policy - require of permission %s without prior declaration.", perm_id); free(perm_id); goto cleanup; } allocated = 1; if ((perm = malloc(sizeof(*perm))) == NULL) { yyerror("Out of memory!"); free(perm_id); goto cleanup; } memset(perm, 0, sizeof(*perm)); ret = hashtab_insert(datum->permissions.table, perm_id, perm); if (ret) { yyerror("Out of memory!"); free(perm_id); free(perm); goto cleanup; } perm->s.value = datum->permissions.nprim + 1; } if (add_perm_to_class(perm->s.value, datum->s.value) == -1) { yyerror("Out of memory!"); goto cleanup; } /* Update number of primitives if we allocated one. */ if (allocated) datum->permissions.nprim++; } return 0; cleanup: return -1; } static int require_role_or_attribute(int pass, unsigned char isattr) { char *id = queue_remove(id_queue); role_datum_t *role = NULL; int retval; if (pass == 2) { free(id); return 0; } if (id == NULL) { yyerror("no role name"); return -1; } if ((role = malloc(sizeof(*role))) == NULL) { free(id); yyerror("Out of memory!"); return -1; } role_datum_init(role); role->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE; retval = require_symbol(SYM_ROLES, id, (hashtab_datum_t *) role, &role->s.value, &role->s.value); if (retval != 0) { free(id); role_datum_destroy(role); free(role); } switch (retval) { case -3:{ yyerror("Out of memory!"); return -1; } case -2:{ yyerror("duplicate declaration of role"); return -1; } case -1:{ yyerror("could not require role here"); return -1; } case 0:{ /* all roles dominate themselves */ if (ebitmap_set_bit (&role->dominates, role->s.value - 1, 1)) { yyerror("Out of memory"); return -1; } return 0; } case 1:{ return 0; /* role already required */ } default:{ assert(0); /* should never get here */ } } } int require_role(int pass) { return require_role_or_attribute(pass, 0); } int require_attribute_role(int pass) { return require_role_or_attribute(pass, 1); } static int require_type_or_attribute(int pass, unsigned char isattr) { char *id = queue_remove(id_queue); type_datum_t *type = NULL; int retval; if (pass == 2) { free(id); return 0; } if (id == NULL) { yyerror("no type name"); return -1; } if ((type = malloc(sizeof(*type))) == NULL) { free(id); yyerror("Out of memory!"); return -1; } type_datum_init(type); type->primary = 1; type->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE; retval = require_symbol(SYM_TYPES, id, (hashtab_datum_t *) type, &type->s.value, &type->s.value); if (retval != 0) { free(id); free(type); } switch (retval) { case -3:{ yyerror("Out of memory!"); return -1; } case -2:{ yyerror("duplicate declaration of type/attribute"); return -1; } case -1:{ yyerror("could not require type/attribute here"); return -1; } case 0:{ return 0; } case 1:{ return 0; /* type already required */ } default:{ assert(0); /* should never get here */ } } } int require_type(int pass) { return require_type_or_attribute(pass, 0); } int require_attribute(int pass) { return require_type_or_attribute(pass, 1); } int require_user(int pass) { char *id = queue_remove(id_queue); user_datum_t *user = NULL; int retval; if (pass == 1) { free(id); return 0; } if (id == NULL) { yyerror("no user name"); return -1; } if ((user = malloc(sizeof(*user))) == NULL) { free(id); yyerror("Out of memory!"); return -1; } user_datum_init(user); retval = require_symbol(SYM_USERS, id, (hashtab_datum_t *) user, &user->s.value, &user->s.value); if (retval != 0) { free(id); user_datum_destroy(user); } switch (retval) { case -3:{ yyerror("Out of memory!"); return -1; } case -2:{ yyerror("duplicate declaration of user"); return -1; } case -1:{ yyerror("could not require user here"); return -1; } case 0:{ return 0; } case 1:{ return 0; /* user already required */ } default:{ assert(0); /* should never get here */ } } } static int require_bool_tunable(int pass, int is_tunable) { char *id = queue_remove(id_queue); cond_bool_datum_t *booldatum = NULL; int retval; if (pass == 2) { free(id); return 0; } if (id == NULL) { yyerror("no boolean name"); return -1; } if ((booldatum = calloc(1, sizeof(*booldatum))) == NULL) { cond_destroy_bool(id, booldatum, NULL); yyerror("Out of memory!"); return -1; } if (is_tunable) booldatum->flags |= COND_BOOL_FLAGS_TUNABLE; retval = require_symbol(SYM_BOOLS, id, (hashtab_datum_t *) booldatum, &booldatum->s.value, &booldatum->s.value); if (retval != 0) { cond_destroy_bool(id, booldatum, NULL); } switch (retval) { case -3:{ yyerror("Out of memory!"); return -1; } case -2:{ yyerror("duplicate declaration of boolean"); return -1; } case -1:{ yyerror("could not require boolean here"); return -1; } case 0:{ return 0; } case 1:{ return 0; /* boolean already required */ } default:{ assert(0); /* should never get here */ } } } int require_bool(int pass) { return require_bool_tunable(pass, 0); } int require_tunable(int pass) { return require_bool_tunable(pass, 1); } int require_sens(int pass) { char *id = queue_remove(id_queue); level_datum_t *level = NULL; int retval; if (pass == 2) { free(id); return 0; } if (!id) { yyerror("no sensitivity name"); return -1; } level = malloc(sizeof(level_datum_t)); if (!level) { free(id); yyerror("Out of memory!"); return -1; } level_datum_init(level); level->level = malloc(sizeof(mls_level_t)); if (!level->level) { free(id); level_datum_destroy(level); free(level); yyerror("Out of memory!"); return -1; } mls_level_init(level->level); retval = require_symbol(SYM_LEVELS, id, (hashtab_datum_t *) level, &level->level->sens, &level->level->sens); if (retval != 0) { free(id); mls_level_destroy(level->level); free(level->level); level_datum_destroy(level); free(level); } switch (retval) { case -3:{ yyerror("Out of memory!"); return -1; } case -2:{ yyerror("duplicate declaration of sensitivity"); return -1; } case -1:{ yyerror("could not require sensitivity here"); return -1; } case 0:{ return 0; } case 1:{ return 0; /* sensitivity already required */ } default:{ assert(0); /* should never get here */ } } } int require_cat(int pass) { char *id = queue_remove(id_queue); cat_datum_t *cat = NULL; int retval; if (pass == 2) { free(id); return 0; } if (!id) { yyerror("no category name"); return -1; } cat = malloc(sizeof(cat_datum_t)); if (!cat) { free(id); yyerror("Out of memory!"); return -1; } cat_datum_init(cat); retval = require_symbol(SYM_CATS, id, (hashtab_datum_t *) cat, &cat->s.value, &cat->s.value); if (retval != 0) { free(id); cat_datum_destroy(cat); free(cat); } switch (retval) { case -3:{ yyerror("Out of memory!"); return -1; } case -2:{ yyerror("duplicate declaration of category"); return -1; } case -1:{ yyerror("could not require category here"); return -1; } case 0:{ return 0; } case 1:{ return 0; /* category already required */ } default:{ assert(0); /* should never get here */ } } } static int is_scope_in_stack(scope_datum_t * scope, scope_stack_t * stack) { int i; if (stack == NULL) { return 0; /* no matching scope found */ } if (stack->type == 1) { avrule_decl_t *decl = stack->decl; for (i = 0; i < scope->decl_ids_len; i++) { if (scope->decl_ids[i] == decl->decl_id) { return 1; } } } else { /* note that conditionals can't declare or require * symbols, so skip this level */ } /* not within scope of this stack, so try its parent */ return is_scope_in_stack(scope, stack->parent); } int is_id_in_scope(uint32_t symbol_type, hashtab_key_t id) { scope_datum_t *scope = (scope_datum_t *) hashtab_search(policydbp->scope[symbol_type]. table, id); if (scope == NULL) { return 1; /* id is not known, so return success */ } return is_scope_in_stack(scope, stack_top); } static int is_perm_in_scope_index(uint32_t perm_value, uint32_t class_value, scope_index_t * scope) { if (class_value > scope->class_perms_len) { return 1; } if (ebitmap_get_bit(scope->class_perms_map + class_value - 1, perm_value - 1)) { return 1; } return 0; } static int is_perm_in_stack(uint32_t perm_value, uint32_t class_value, scope_stack_t * stack) { if (stack == NULL) { return 0; /* no matching scope found */ } if (stack->type == 1) { avrule_decl_t *decl = stack->decl; if (is_perm_in_scope_index (perm_value, class_value, &decl->required) || is_perm_in_scope_index(perm_value, class_value, &decl->declared)) { return 1; } } else { /* note that conditionals can't declare or require * symbols, so skip this level */ } /* not within scope of this stack, so try its parent */ return is_perm_in_stack(perm_value, class_value, stack->parent); } int is_perm_in_scope(hashtab_key_t perm_id, hashtab_key_t class_id) { class_datum_t *cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, class_id); perm_datum_t *perdatum; if (cladatum == NULL) { return 1; } perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table, perm_id); if (perdatum == NULL) { return 1; } return is_perm_in_stack(perdatum->s.value, cladatum->s.value, stack_top); } cond_list_t *get_current_cond_list(cond_list_t * cond) { /* FIX ME: do something different here if in a nested * conditional? */ avrule_decl_t *decl = stack_top->decl; return get_decl_cond_list(policydbp, decl, cond); } /* Append the new conditional node to the existing ones. During * expansion the list will be reversed -- i.e., the last AV rule will * be the first one listed in the policy. This matches the behavior * of the upstream compiler. */ void append_cond_list(cond_list_t * cond) { cond_list_t *old_cond = get_current_cond_list(cond); avrule_t *tmp; assert(old_cond != NULL); /* probably out of memory */ if (old_cond->avtrue_list == NULL) { old_cond->avtrue_list = cond->avtrue_list; } else { for (tmp = old_cond->avtrue_list; tmp->next != NULL; tmp = tmp->next) ; tmp->next = cond->avtrue_list; } if (old_cond->avfalse_list == NULL) { old_cond->avfalse_list = cond->avfalse_list; } else { for (tmp = old_cond->avfalse_list; tmp->next != NULL; tmp = tmp->next) ; tmp->next = cond->avfalse_list; } old_cond->flags |= cond->flags; } void append_avrule(avrule_t * avrule) { avrule_decl_t *decl = stack_top->decl; /* currently avrules follow a completely different code path * for handling avrules and compute types * (define_cond_avrule_te_avtab, define_cond_compute_type); * therefore there ought never be a conditional on top of the * scope stack */ assert(stack_top->type == 1); if (stack_top->last_avrule == NULL) { decl->avrules = avrule; } else { stack_top->last_avrule->next = avrule; } stack_top->last_avrule = avrule; } /* this doesn't actually append, but really prepends it */ void append_role_trans(role_trans_rule_t * role_tr_rules) { avrule_decl_t *decl = stack_top->decl; /* role transitions are not allowed within conditionals */ assert(stack_top->type == 1); role_tr_rules->next = decl->role_tr_rules; decl->role_tr_rules = role_tr_rules; } /* this doesn't actually append, but really prepends it */ void append_role_allow(role_allow_rule_t * role_allow_rules) { avrule_decl_t *decl = stack_top->decl; /* role allows are not allowed within conditionals */ assert(stack_top->type == 1); role_allow_rules->next = decl->role_allow_rules; decl->role_allow_rules = role_allow_rules; } /* this doesn't actually append, but really prepends it */ void append_filename_trans(filename_trans_rule_t * filename_trans_rules) { avrule_decl_t *decl = stack_top->decl; /* filename transitions are not allowed within conditionals */ assert(stack_top->type == 1); filename_trans_rules->next = decl->filename_trans_rules; decl->filename_trans_rules = filename_trans_rules; } /* this doesn't actually append, but really prepends it */ void append_range_trans(range_trans_rule_t * range_tr_rules) { avrule_decl_t *decl = stack_top->decl; /* range transitions are not allowed within conditionals */ assert(stack_top->type == 1); range_tr_rules->next = decl->range_tr_rules; decl->range_tr_rules = range_tr_rules; } int begin_optional(int pass) { avrule_block_t *block = NULL; avrule_decl_t *decl; if (pass == 1) { /* allocate a new avrule block for this optional block */ if ((block = avrule_block_create()) == NULL || (decl = avrule_decl_create(next_decl_id)) == NULL) { goto cleanup; } block->flags |= AVRULE_OPTIONAL; block->branch_list = decl; last_block->next = block; } else { /* select the next block from the chain built during pass 1 */ block = last_block->next; assert(block != NULL && block->branch_list != NULL && block->branch_list->decl_id == next_decl_id); decl = block->branch_list; } if (push_stack(1, block, decl) == -1) { goto cleanup; } stack_top->last_avrule = NULL; last_block = block; next_decl_id++; return 0; cleanup: yyerror("Out of memory!"); avrule_block_destroy(block); return -1; } int end_optional(int pass) { /* once nested conditionals are allowed, do the stack unfolding here */ pop_stack(); return 0; } int begin_optional_else(int pass) { avrule_decl_t *decl; assert(stack_top->type == 1 && stack_top->in_else == 0); if (pass == 1) { /* allocate a new declaration and add it to the * current chain */ if ((decl = avrule_decl_create(next_decl_id)) == NULL) { yyerror("Out of memory!"); return -1; } stack_top->decl->next = decl; } else { /* pick the (hopefully last) declaration of this avrule block, built from pass 1 */ decl = stack_top->decl->next; assert(decl != NULL && decl->next == NULL && decl->decl_id == next_decl_id); } stack_top->in_else = 1; stack_top->decl = decl; stack_top->last_avrule = NULL; stack_top->require_given = 0; next_decl_id++; return 0; } static int copy_requirements(avrule_decl_t * dest, scope_stack_t * stack) { int i; if (stack == NULL) { return 0; } if (stack->type == 1) { scope_index_t *src_scope = &stack->decl->required; scope_index_t *dest_scope = &dest->required; for (i = 0; i < SYM_NUM; i++) { ebitmap_t *src_bitmap = &src_scope->scope[i]; ebitmap_t *dest_bitmap = &dest_scope->scope[i]; if (ebitmap_union(dest_bitmap, src_bitmap)) { yyerror("Out of memory!"); return -1; } } /* now copy class permissions */ if (src_scope->class_perms_len > dest_scope->class_perms_len) { ebitmap_t *new_map = realloc(dest_scope->class_perms_map, src_scope->class_perms_len * sizeof(*new_map)); if (new_map == NULL) { yyerror("Out of memory!"); return -1; } dest_scope->class_perms_map = new_map; for (i = dest_scope->class_perms_len; i < src_scope->class_perms_len; i++) { ebitmap_init(dest_scope->class_perms_map + i); } dest_scope->class_perms_len = src_scope->class_perms_len; } for (i = 0; i < src_scope->class_perms_len; i++) { ebitmap_t *src_bitmap = &src_scope->class_perms_map[i]; ebitmap_t *dest_bitmap = &dest_scope->class_perms_map[i]; if (ebitmap_union(dest_bitmap, src_bitmap)) { yyerror("Out of memory!"); return -1; } } } return copy_requirements(dest, stack->parent); } /* During pass 1, check that at least one thing was required within * this block, for those places where a REQUIRED is necessary. During * pass 2, have this block inherit its parents' requirements. Return * 0 on success, -1 on failure. */ int end_avrule_block(int pass) { avrule_decl_t *decl = stack_top->decl; assert(stack_top->type == 1); if (pass == 2) { /* this avrule_decl inherits all of its parents' * requirements */ if (copy_requirements(decl, stack_top->parent) == -1) { return -1; } return 0; } if (!stack_top->in_else && !stack_top->require_given) { if (policydbp->policy_type == POLICY_BASE && stack_top->parent != NULL) { /* if this is base no require should be in the global block */ return 0; } else { /* non-ELSE branches must have at least one thing required */ yyerror("This block has no require section."); return -1; } } return 0; } /* Push a new scope on to the stack and update the 'last' pointer. * Return 0 on success, -1 if out * of memory. */ static int push_stack(int stack_type, ...) { scope_stack_t *s = calloc(1, sizeof(*s)); va_list ap; if (s == NULL) { return -1; } va_start(ap, stack_type); switch (s->type = stack_type) { case 1:{ s->u.avrule = va_arg(ap, avrule_block_t *); s->decl = va_arg(ap, avrule_decl_t *); break; } case 2:{ s->u.cond_list = va_arg(ap, cond_list_t *); break; } default: /* invalid stack type given */ assert(0); } va_end(ap); s->parent = stack_top; s->child = NULL; stack_top = s; return 0; } /* Pop off the most recently added from the stack. Update the 'last' * pointer. */ static void pop_stack(void) { scope_stack_t *parent; assert(stack_top != NULL); parent = stack_top->parent; if (parent != NULL) { parent->child = NULL; } free(stack_top); stack_top = parent; } checkpolicy-2.2/module_compiler.h000066400000000000000000000106141223423440700172050ustar00rootroot00000000000000/* Author : Joshua Brindle * Karl MacMillan * Jason Tang * Added support for binary policy modules * * Copyright (C) 2004 - 2005 Tresys Technology, LLC * 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. */ #ifndef MODULE_COMPILER_H #define MODULE_COMPILER_H #include /* Called when checkpolicy begins to parse a policy -- either at the * very beginning for a kernel/base policy, or after the module header * for policy modules. Initialize the memory structures within. * Return 0 on success, -1 on error. */ int define_policy(int pass, int module_header_given); /* Declare a symbol declaration to the current avrule_decl. Check * that insertion is allowed here and that the symbol does not already * exist. Returns 0 on success, 1 if symbol was already there (caller * needs to free() the datum), -1 if declarations not allowed, -2 for * duplicate declarations, -3 for all else. */ int declare_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value); role_datum_t *declare_role(unsigned char isattr); type_datum_t *declare_type(unsigned char primary, unsigned char isattr); user_datum_t *declare_user(void); type_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr); role_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr); /* Add a symbol to the current avrule_block's require section. Note * that a module may not both declare and require the same symbol. * Returns 0 on success, -1 on error. */ int require_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum, uint32_t * dest_value, uint32_t * datum_value); /* Enable a permission for a class within the current avrule_decl. * Return 0 on success, -1 if out of memory. */ int add_perm_to_class(uint32_t perm_value, uint32_t class_value); /* Functions called from REQUIRE blocks. Add the first symbol on the * id_queue to this avrule_decl's scope if not already there. * c.f. require_symbol(). */ int require_class(int pass); int require_role(int pass); int require_type(int pass); int require_attribute(int pass); int require_attribute_role(int pass); int require_user(int pass); int require_bool(int pass); int require_tunable(int pass); int require_sens(int pass); int require_cat(int pass); /* Check if an identifier is within the scope of the current * declaration or any of its parents. Return 1 if it is, 0 if not. * If the identifier is not known at all then return 1 (truth). */ int is_id_in_scope(uint32_t symbol_type, hashtab_key_t id); /* Check if a particular permission is within the scope of the current * declaration or any of its parents. Return 1 if it is, 0 if not. * If the identifier is not known at all then return 1 (truth). */ int is_perm_in_scope(hashtab_key_t perm_id, hashtab_key_t class_id); /* Search the current avrules block for a conditional with the same * expression as 'cond'. If the conditional does not exist then * create one. Either way, return the conditional. */ cond_list_t *get_current_cond_list(cond_list_t * cond); /* Append rule to the current avrule_block. */ void append_cond_list(cond_list_t * cond); void append_avrule(avrule_t * avrule); void append_role_trans(role_trans_rule_t * role_tr_rules); void append_role_allow(role_allow_rule_t * role_allow_rules); void append_range_trans(range_trans_rule_t * range_tr_rules); void append_filename_trans(filename_trans_rule_t * filename_trans_rules); /* Create a new optional block and add it to the global policy. * During the second pass resolve the block's requirements. Return 0 * on success, -1 on error. */ int begin_optional(int pass); int end_optional(int pass); /* ELSE blocks are similar to normal blocks with the following two * limitations: * - no declarations are allowed within else branches * - no REQUIRES are allowed; the else branch inherits the parent's * requirements */ int begin_optional_else(int pass); /* Called whenever existing an avrule block. Check that the block had * a non-empty REQUIRE section. If so pop the block off of the scop * stack and return 0. If not then send an error to yyerror and * return -1. */ int end_avrule_block(int pass); #endif checkpolicy-2.2/parse_util.c000066400000000000000000000041271223423440700161720ustar00rootroot00000000000000/* * Author: Karl MacMillan * * Copyright (C) 2006 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "parse_util.h" #include "queue.h" /* these are defined in policy_parse.y and are needed for read_source_policy */ extern FILE *yyin; extern void init_parser(int); extern int yyparse(void); extern void yyrestart(FILE *); extern queue_t id_queue; extern unsigned int policydb_errors; extern unsigned long policydb_lineno; extern policydb_t *policydbp; extern int mlspol; extern void set_source_file(const char *name); int read_source_policy(policydb_t * p, const char *file, const char *progname) { yyin = fopen(file, "r"); if (!yyin) { fprintf(stderr, "%s: unable to open %s\n", progname, file); return -1; } set_source_file(file); if ((id_queue = queue_create()) == NULL) { fprintf(stderr, "%s: out of memory!\n", progname); return -1; } policydbp = p; mlspol = p->mls; init_parser(1); if (yyparse() || policydb_errors) { fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", progname); return -1; } rewind(yyin); init_parser(2); set_source_file(file); yyrestart(yyin); if (yyparse() || policydb_errors) { fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", progname); return -1; } queue_destroy(id_queue); if (policydb_errors) return -1; fclose(yyin); return 0; } checkpolicy-2.2/parse_util.h000066400000000000000000000025251223423440700161770ustar00rootroot00000000000000/* * Author: Karl MacMillan * * Copyright (C) 2006 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Utility functions shared by checkpolicy and checkmodule */ #ifndef __PARSE_UTIL_H__ #define __PARSE_UTIL_H__ #include /* Read a source policy and populate the policydb passed in. The * policydb must already have been created and configured (e.g., * expected policy type set. The string progname is used for * error messages. No checking of assertions, hierarchy, etc. * is done. */ int read_source_policy(policydb_t * p, const char *file, const char *progname); #endif checkpolicy-2.2/policy_define.c000066400000000000000000002743021223423440700166400ustar00rootroot00000000000000/* * Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: David Caplan, * * Added conditional policy language extensions * * Updated: Joshua Brindle * Karl MacMillan * Jason Tang * * Added support for binary policy modules * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2008 Tresys Technology, LLC * Copyright (C) 2007 Red Hat Inc. * 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. */ /* FLASK */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "queue.h" #include "checkpolicy.h" #include "module_compiler.h" #include "policy_define.h" policydb_t *policydbp; queue_t id_queue = 0; unsigned int pass; char *curfile = 0; int mlspol = 0; extern unsigned long policydb_lineno; extern unsigned long source_lineno; extern unsigned int policydb_errors; extern int yywarn(char *msg); extern int yyerror(char *msg); #define ERRORMSG_LEN 255 static char errormsg[ERRORMSG_LEN + 1] = {0}; static int id_has_dot(char *id); static int parse_security_context(context_struct_t *c); /* initialize all of the state variables for the scanner/parser */ void init_parser(int pass_number) { policydb_lineno = 1; source_lineno = 1; policydb_errors = 0; pass = pass_number; } void yyerror2(char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(errormsg, ERRORMSG_LEN, fmt, ap); yyerror(errormsg); va_end(ap); } int insert_separator(int push) { int error; if (push) error = queue_push(id_queue, 0); else error = queue_insert(id_queue, 0); if (error) { yyerror("queue overflow"); return -1; } return 0; } int insert_id(char *id, int push) { char *newid = 0; int error; newid = (char *)malloc(strlen(id) + 1); if (!newid) { yyerror("out of memory"); return -1; } strcpy(newid, id); if (push) error = queue_push(id_queue, (queue_element_t) newid); else error = queue_insert(id_queue, (queue_element_t) newid); if (error) { yyerror("queue overflow"); free(newid); return -1; } return 0; } /* If the identifier has a dot within it and that its first character is not a dot then return 1, else return 0. */ static int id_has_dot(char *id) { if (strchr(id, '.') >= id + 1) { return 1; } return 0; } int define_class(void) { char *id = 0; class_datum_t *datum = 0; int ret; uint32_t value; if (pass == 2) { id = queue_remove(id_queue); free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no class name for class definition?"); return -1; } datum = (class_datum_t *) malloc(sizeof(class_datum_t)); if (!datum) { yyerror("out of memory"); goto bad; } memset(datum, 0, sizeof(class_datum_t)); ret = declare_symbol(SYM_CLASSES, id, datum, &value, &value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto bad; } case -2:{ yyerror2("duplicate declaration of class %s", id); goto bad; } case -1:{ yyerror("could not declare class here"); goto bad; } case 0: case 1:{ break; } default:{ assert(0); /* should never get here */ } } datum->s.value = value; return 0; bad: if (id) free(id); if (datum) free(datum); return -1; } int define_permissive(void) { char *type = NULL; struct type_datum *t; int rc = 0; type = queue_remove(id_queue); if (!type) { yyerror2("forgot to include type in permissive definition?"); rc = -1; goto out; } if (pass == 1) goto out; if (!is_id_in_scope(SYM_TYPES, type)) { yyerror2("type %s is not within scope", type); rc = -1; goto out; } t = hashtab_search(policydbp->p_types.table, type); if (!t) { yyerror2("type is not defined: %s", type); rc = -1; goto out; } if (t->flavor == TYPE_ATTRIB) { yyerror2("attributes may not be permissive: %s\n", type); rc = -1; goto out; } t->flags |= TYPE_FLAGS_PERMISSIVE; out: free(type); return rc; } int define_polcap(void) { char *id = 0; int capnum; if (pass == 2) { id = queue_remove(id_queue); free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no capability name for policycap definition?"); goto bad; } /* Check for valid cap name -> number mapping */ capnum = sepol_polcap_getnum(id); if (capnum < 0) { yyerror2("invalid policy capability name %s", id); goto bad; } /* Store it */ if (ebitmap_set_bit(&policydbp->policycaps, capnum, TRUE)) { yyerror("out of memory"); goto bad; } free(id); return 0; bad: free(id); return -1; } int define_initial_sid(void) { char *id = 0; ocontext_t *newc = 0, *c, *head; if (pass == 2) { id = queue_remove(id_queue); free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no sid name for SID definition?"); return -1; } newc = (ocontext_t *) malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); goto bad; } memset(newc, 0, sizeof(ocontext_t)); newc->u.name = id; context_init(&newc->context[0]); head = policydbp->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { if (!strcmp(newc->u.name, c->u.name)) { yyerror2("duplicate initial SID %s", id); goto bad; } } if (head) { newc->sid[0] = head->sid[0] + 1; } else { newc->sid[0] = 1; } newc->next = head; policydbp->ocontexts[OCON_ISID] = newc; return 0; bad: if (id) free(id); if (newc) free(newc); return -1; } static int read_classes(ebitmap_t *e_classes) { char *id; class_datum_t *cladatum; while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (ebitmap_set_bit(e_classes, cladatum->s.value - 1, TRUE)) { yyerror("Out of memory"); return -1; } free(id); } return 0; } int define_default_user(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_user && cladatum->default_user != which) { yyerror2("conflicting default user information for class %s", id); return -1; } cladatum->default_user = which; free(id); } return 0; } int define_default_role(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_role && cladatum->default_role != which) { yyerror2("conflicting default role information for class %s", id); return -1; } cladatum->default_role = which; free(id); } return 0; } int define_default_type(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_type && cladatum->default_type != which) { yyerror2("conflicting default type information for class %s", id); return -1; } cladatum->default_type = which; free(id); } return 0; } int define_default_range(int which) { char *id; class_datum_t *cladatum; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); return -1; } cladatum = hashtab_search(policydbp->p_classes.table, id); if (!cladatum) { yyerror2("unknown class %s", id); return -1; } if (cladatum->default_range && cladatum->default_range != which) { yyerror2("conflicting default range information for class %s", id); return -1; } cladatum->default_range = which; free(id); } return 0; } int define_common_perms(void) { char *id = 0, *perm = 0; common_datum_t *comdatum = 0; perm_datum_t *perdatum = 0; int ret; if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no common name for common perm definition?"); return -1; } comdatum = hashtab_search(policydbp->p_commons.table, id); if (comdatum) { yyerror2("duplicate declaration for common %s\n", id); return -1; } comdatum = (common_datum_t *) malloc(sizeof(common_datum_t)); if (!comdatum) { yyerror("out of memory"); goto bad; } memset(comdatum, 0, sizeof(common_datum_t)); ret = hashtab_insert(policydbp->p_commons.table, (hashtab_key_t) id, (hashtab_datum_t) comdatum); if (ret == SEPOL_EEXIST) { yyerror("duplicate common definition"); goto bad; } if (ret == SEPOL_ENOMEM) { yyerror("hash table overflow"); goto bad; } comdatum->s.value = policydbp->p_commons.nprim + 1; if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE)) { yyerror("out of memory"); goto bad; } policydbp->p_commons.nprim++; while ((perm = queue_remove(id_queue))) { perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t)); if (!perdatum) { yyerror("out of memory"); goto bad_perm; } memset(perdatum, 0, sizeof(perm_datum_t)); perdatum->s.value = comdatum->permissions.nprim + 1; if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) { yyerror ("too many permissions to fit in an access vector"); goto bad_perm; } ret = hashtab_insert(comdatum->permissions.table, (hashtab_key_t) perm, (hashtab_datum_t) perdatum); if (ret == SEPOL_EEXIST) { yyerror2("duplicate permission %s in common %s", perm, id); goto bad_perm; } if (ret == SEPOL_ENOMEM) { yyerror("hash table overflow"); goto bad_perm; } comdatum->permissions.nprim++; } return 0; bad: if (id) free(id); if (comdatum) free(comdatum); return -1; bad_perm: if (perm) free(perm); if (perdatum) free(perdatum); return -1; } int define_av_perms(int inherits) { char *id; class_datum_t *cladatum; common_datum_t *comdatum; perm_datum_t *perdatum = 0, *perdatum2 = 0; int ret; if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no tclass name for av perm definition?"); return -1; } cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, (hashtab_key_t) id); if (!cladatum) { yyerror2("class %s is not defined", id); goto bad; } free(id); if (cladatum->comdatum || cladatum->permissions.nprim) { yyerror("duplicate access vector definition"); return -1; } if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE)) { yyerror("out of memory"); return -1; } if (inherits) { id = (char *)queue_remove(id_queue); if (!id) { yyerror ("no inherits name for access vector definition?"); return -1; } comdatum = (common_datum_t *) hashtab_search(policydbp->p_commons. table, (hashtab_key_t) id); if (!comdatum) { yyerror2("common %s is not defined", id); goto bad; } cladatum->comkey = id; cladatum->comdatum = comdatum; /* * Class-specific permissions start with values * after the last common permission. */ cladatum->permissions.nprim += comdatum->permissions.nprim; } while ((id = queue_remove(id_queue))) { perdatum = (perm_datum_t *) malloc(sizeof(perm_datum_t)); if (!perdatum) { yyerror("out of memory"); goto bad; } memset(perdatum, 0, sizeof(perm_datum_t)); perdatum->s.value = ++cladatum->permissions.nprim; if (perdatum->s.value > (sizeof(sepol_access_vector_t) * 8)) { yyerror ("too many permissions to fit in an access vector"); goto bad; } if (inherits) { /* * Class-specific permissions and * common permissions exist in the same * name space. */ perdatum2 = (perm_datum_t *) hashtab_search(cladatum->comdatum-> permissions.table, (hashtab_key_t) id); if (perdatum2) { yyerror2("permission %s conflicts with an " "inherited permission", id); goto bad; } } ret = hashtab_insert(cladatum->permissions.table, (hashtab_key_t) id, (hashtab_datum_t) perdatum); if (ret == SEPOL_EEXIST) { yyerror2("duplicate permission %s", id); goto bad; } if (ret == SEPOL_ENOMEM) { yyerror("hash table overflow"); goto bad; } if (add_perm_to_class(perdatum->s.value, cladatum->s.value)) { yyerror("out of memory"); goto bad; } } return 0; bad: if (id) free(id); if (perdatum) free(perdatum); return -1; } int define_sens(void) { char *id; mls_level_t *level = 0; level_datum_t *datum = 0, *aliasdatum = 0; int ret; uint32_t value; /* dummy variable -- its value is never used */ if (!mlspol) { yyerror("sensitivity definition in non-MLS configuration"); return -1; } if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no sensitivity name for sensitivity definition?"); return -1; } if (id_has_dot(id)) { yyerror("sensitivity identifiers may not contain periods"); goto bad; } level = (mls_level_t *) malloc(sizeof(mls_level_t)); if (!level) { yyerror("out of memory"); goto bad; } mls_level_init(level); level->sens = 0; /* actual value set in define_dominance */ ebitmap_init(&level->cat); /* actual value set in define_level */ datum = (level_datum_t *) malloc(sizeof(level_datum_t)); if (!datum) { yyerror("out of memory"); goto bad; } level_datum_init(datum); datum->isalias = FALSE; datum->level = level; ret = declare_symbol(SYM_LEVELS, id, datum, &value, &value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto bad; } case -2:{ yyerror("duplicate declaration of sensitivity level"); goto bad; } case -1:{ yyerror("could not declare sensitivity level here"); goto bad; } case 0: case 1:{ break; } default:{ assert(0); /* should never get here */ } } while ((id = queue_remove(id_queue))) { if (id_has_dot(id)) { yyerror("sensitivity aliases may not contain periods"); goto bad_alias; } aliasdatum = (level_datum_t *) malloc(sizeof(level_datum_t)); if (!aliasdatum) { yyerror("out of memory"); goto bad_alias; } level_datum_init(aliasdatum); aliasdatum->isalias = TRUE; aliasdatum->level = level; ret = declare_symbol(SYM_LEVELS, id, aliasdatum, NULL, &value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto bad_alias; } case -2:{ yyerror ("duplicate declaration of sensitivity alias"); goto bad_alias; } case -1:{ yyerror ("could not declare sensitivity alias here"); goto bad_alias; } case 0: case 1:{ break; } default:{ assert(0); /* should never get here */ } } } return 0; bad: if (id) free(id); if (level) free(level); if (datum) { level_datum_destroy(datum); free(datum); } return -1; bad_alias: if (id) free(id); if (aliasdatum) { level_datum_destroy(aliasdatum); free(aliasdatum); } return -1; } int define_dominance(void) { level_datum_t *datum; int order; char *id; if (!mlspol) { yyerror("dominance definition in non-MLS configuration"); return -1; } if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } order = 0; while ((id = (char *)queue_remove(id_queue))) { datum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id); if (!datum) { yyerror2("unknown sensitivity %s used in dominance " "definition", id); free(id); return -1; } if (datum->level->sens != 0) { yyerror2("sensitivity %s occurs multiply in dominance " "definition", id); free(id); return -1; } datum->level->sens = ++order; /* no need to keep sensitivity name */ free(id); } if (order != policydbp->p_levels.nprim) { yyerror ("all sensitivities must be specified in dominance definition"); return -1; } return 0; } int define_category(void) { char *id; cat_datum_t *datum = 0, *aliasdatum = 0; int ret; uint32_t value; if (!mlspol) { yyerror("category definition in non-MLS configuration"); return -1; } if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no category name for category definition?"); return -1; } if (id_has_dot(id)) { yyerror("category identifiers may not contain periods"); goto bad; } datum = (cat_datum_t *) malloc(sizeof(cat_datum_t)); if (!datum) { yyerror("out of memory"); goto bad; } cat_datum_init(datum); datum->isalias = FALSE; ret = declare_symbol(SYM_CATS, id, datum, &value, &value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto bad; } case -2:{ yyerror("duplicate declaration of category"); goto bad; } case -1:{ yyerror("could not declare category here"); goto bad; } case 0: case 1:{ break; } default:{ assert(0); /* should never get here */ } } datum->s.value = value; while ((id = queue_remove(id_queue))) { if (id_has_dot(id)) { yyerror("category aliases may not contain periods"); goto bad_alias; } aliasdatum = (cat_datum_t *) malloc(sizeof(cat_datum_t)); if (!aliasdatum) { yyerror("out of memory"); goto bad_alias; } cat_datum_init(aliasdatum); aliasdatum->isalias = TRUE; aliasdatum->s.value = datum->s.value; ret = declare_symbol(SYM_CATS, id, aliasdatum, NULL, &datum->s.value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto bad_alias; } case -2:{ yyerror ("duplicate declaration of category aliases"); goto bad_alias; } case -1:{ yyerror ("could not declare category aliases here"); goto bad_alias; } case 0: case 1:{ break; } default:{ assert(0); /* should never get here */ } } } return 0; bad: if (id) free(id); if (datum) { cat_datum_destroy(datum); free(datum); } return -1; bad_alias: if (id) free(id); if (aliasdatum) { cat_datum_destroy(aliasdatum); free(aliasdatum); } return -1; } static int clone_level(hashtab_key_t key, hashtab_datum_t datum, void *arg) { level_datum_t *levdatum = (level_datum_t *) datum; mls_level_t *level = (mls_level_t *) arg, *newlevel; if (levdatum->level == level) { levdatum->defined = 1; if (!levdatum->isalias) return 0; newlevel = (mls_level_t *) malloc(sizeof(mls_level_t)); if (!newlevel) return -1; if (mls_level_cpy(newlevel, level)) { free(newlevel); return -1; } levdatum->level = newlevel; } return 0; } int define_level(void) { char *id; level_datum_t *levdatum; if (!mlspol) { yyerror("level definition in non-MLS configuration"); return -1; } if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no level name for level definition?"); return -1; } levdatum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id); if (!levdatum) { yyerror2("unknown sensitivity %s used in level definition", id); free(id); return -1; } if (ebitmap_length(&levdatum->level->cat)) { yyerror2("sensitivity %s used in multiple level definitions", id); free(id); return -1; } free(id); levdatum->defined = 1; while ((id = queue_remove(id_queue))) { cat_datum_t *cdatum; int range_start, range_end, i; if (id_has_dot(id)) { char *id_start = id; char *id_end = strchr(id, '.'); *(id_end++) = '\0'; cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats. table, (hashtab_key_t) id_start); if (!cdatum) { yyerror2("unknown category %s", id_start); free(id); return -1; } range_start = cdatum->s.value - 1; cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats. table, (hashtab_key_t) id_end); if (!cdatum) { yyerror2("unknown category %s", id_end); free(id); return -1; } range_end = cdatum->s.value - 1; if (range_end < range_start) { yyerror2("category range is invalid"); free(id); return -1; } } else { cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats. table, (hashtab_key_t) id); range_start = range_end = cdatum->s.value - 1; } for (i = range_start; i <= range_end; i++) { if (ebitmap_set_bit(&levdatum->level->cat, i, TRUE)) { yyerror("out of memory"); free(id); return -1; } } free(id); } if (hashtab_map (policydbp->p_levels.table, clone_level, levdatum->level)) { yyerror("out of memory"); return -1; } return 0; } int define_attrib(void) { if (pass == 2) { free(queue_remove(id_queue)); return 0; } if (declare_type(TRUE, TRUE) == NULL) { return -1; } return 0; } static int add_aliases_to_type(type_datum_t * type) { char *id; type_datum_t *aliasdatum = NULL; int ret; while ((id = queue_remove(id_queue))) { if (id_has_dot(id)) { free(id); yyerror ("type alias identifiers may not contain periods"); return -1; } aliasdatum = (type_datum_t *) malloc(sizeof(type_datum_t)); if (!aliasdatum) { free(id); yyerror("Out of memory!"); return -1; } memset(aliasdatum, 0, sizeof(type_datum_t)); aliasdatum->s.value = type->s.value; ret = declare_symbol(SYM_TYPES, id, aliasdatum, NULL, &aliasdatum->s.value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto cleanup; } case -2:{ yyerror2("duplicate declaration of alias %s", id); goto cleanup; } case -1:{ yyerror("could not declare alias here"); goto cleanup; } case 0: break; case 1:{ /* ret == 1 means the alias was required and therefore already * has a value. Set it up as an alias with a different primary. */ type_datum_destroy(aliasdatum); free(aliasdatum); aliasdatum = hashtab_search(policydbp->symtab[SYM_TYPES].table, id); assert(aliasdatum); aliasdatum->primary = type->s.value; aliasdatum->flavor = TYPE_ALIAS; break; } default:{ assert(0); /* should never get here */ } } } return 0; cleanup: free(id); type_datum_destroy(aliasdatum); free(aliasdatum); return -1; } int define_typealias(void) { char *id; type_datum_t *t; if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no type name for typealias definition?"); return -1; } if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("type %s is not within scope", id); free(id); return -1; } t = hashtab_search(policydbp->p_types.table, id); if (!t || t->flavor == TYPE_ATTRIB) { yyerror2("unknown type %s, or it was already declared as an " "attribute", id); free(id); return -1; } return add_aliases_to_type(t); } int define_typeattribute(void) { char *id; type_datum_t *t, *attr; if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no type name for typeattribute definition?"); return -1; } if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("type %s is not within scope", id); free(id); return -1; } t = hashtab_search(policydbp->p_types.table, id); if (!t || t->flavor == TYPE_ATTRIB) { yyerror2("unknown type %s", id); free(id); return -1; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("attribute %s is not within scope", id); free(id); return -1; } attr = hashtab_search(policydbp->p_types.table, id); if (!attr) { /* treat it as a fatal error */ yyerror2("attribute %s is not declared", id); free(id); return -1; } if (attr->flavor != TYPE_ATTRIB) { yyerror2("%s is a type, not an attribute", id); free(id); return -1; } if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) { yyerror("Out of memory!"); return -1; } if (ebitmap_set_bit(&attr->types, (t->s.value - 1), TRUE)) { yyerror("out of memory"); return -1; } } return 0; } static int define_typebounds_helper(char *bounds_id, char *type_id) { type_datum_t *bounds, *type; if (!is_id_in_scope(SYM_TYPES, bounds_id)) { yyerror2("type %s is not within scope", bounds_id); return -1; } bounds = hashtab_search(policydbp->p_types.table, bounds_id); if (!bounds || bounds->flavor == TYPE_ATTRIB) { yyerror2("hoge unknown type %s", bounds_id); return -1; } if (!is_id_in_scope(SYM_TYPES, type_id)) { yyerror2("type %s is not within scope", type_id); return -1; } type = hashtab_search(policydbp->p_types.table, type_id); if (!type || type->flavor == TYPE_ATTRIB) { yyerror2("type %s is not declared", type_id); return -1; } if (type->flavor == TYPE_TYPE && !type->primary) { type = policydbp->type_val_to_struct[type->s.value - 1]; } else if (type->flavor == TYPE_ALIAS) { type = policydbp->type_val_to_struct[type->primary - 1]; } if (!type->bounds) type->bounds = bounds->s.value; else if (type->bounds != bounds->s.value) { yyerror2("type %s has inconsistent master {%s,%s}", type_id, policydbp->p_type_val_to_name[type->bounds - 1], policydbp->p_type_val_to_name[bounds->s.value - 1]); return -1; } return 0; } int define_typebounds(void) { char *bounds, *id; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } bounds = (char *) queue_remove(id_queue); if (!bounds) { yyerror("no type name for typebounds definition?"); return -1; } while ((id = queue_remove(id_queue))) { if (define_typebounds_helper(bounds, id)) return -1; free(id); } free(bounds); return 0; } int define_type(int alias) { char *id; type_datum_t *datum, *attr; if (pass == 2) { /* * If type name contains ".", we have to define boundary * relationship implicitly to keep compatibility with * old name based hierarchy. */ if ((id = queue_remove(id_queue))) { char *bounds, *delim; if ((delim = strrchr(id, '.')) && (bounds = strdup(id))) { bounds[(size_t)(delim - id)] = '\0'; if (define_typebounds_helper(bounds, id)) return -1; free(bounds); } free(id); } if (alias) { while ((id = queue_remove(id_queue))) free(id); } while ((id = queue_remove(id_queue))) free(id); return 0; } if ((datum = declare_type(TRUE, FALSE)) == NULL) { return -1; } if (alias) { if (add_aliases_to_type(datum) == -1) { return -1; } } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("attribute %s is not within scope", id); free(id); return -1; } attr = hashtab_search(policydbp->p_types.table, id); if (!attr) { /* treat it as a fatal error */ yyerror2("attribute %s is not declared", id); return -1; } if (attr->flavor != TYPE_ATTRIB) { yyerror2("%s is a type, not an attribute", id); return -1; } if ((attr = get_local_type(id, attr->s.value, 1)) == NULL) { yyerror("Out of memory!"); return -1; } if (ebitmap_set_bit(&attr->types, datum->s.value - 1, TRUE)) { yyerror("Out of memory"); return -1; } } return 0; } struct val_to_name { unsigned int val; char *name; }; /* Adds a type, given by its textual name, to a typeset. If *add is 0, then add the type to the negative set; otherwise if *add is 1 then add it to the positive side. */ static int set_types(type_set_t * set, char *id, int *add, char starallowed) { type_datum_t *t; if (strcmp(id, "*") == 0) { if (!starallowed) { yyerror("* not allowed in this type of rule"); return -1; } /* set TYPE_STAR flag */ set->flags = TYPE_STAR; free(id); *add = 1; return 0; } if (strcmp(id, "~") == 0) { if (!starallowed) { yyerror("~ not allowed in this type of rule"); return -1; } /* complement the set */ set->flags = TYPE_COMP; free(id); *add = 1; return 0; } if (strcmp(id, "-") == 0) { *add = 0; free(id); return 0; } if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("type %s is not within scope", id); free(id); return -1; } t = hashtab_search(policydbp->p_types.table, id); if (!t) { yyerror2("unknown type %s", id); free(id); return -1; } if (*add == 0) { if (ebitmap_set_bit(&set->negset, t->s.value - 1, TRUE)) goto oom; } else { if (ebitmap_set_bit(&set->types, t->s.value - 1, TRUE)) goto oom; } free(id); *add = 1; return 0; oom: yyerror("Out of memory"); free(id); return -1; } int define_compute_type_helper(int which, avrule_t ** rule) { char *id; type_datum_t *datum; ebitmap_t tclasses; ebitmap_node_t *node; avrule_t *avrule; class_perm_node_t *perm; int i, add = 1; avrule = malloc(sizeof(avrule_t)); if (!avrule) { yyerror("out of memory"); return -1; } avrule_init(avrule); avrule->specified = which; avrule->line = policydb_lineno; while ((id = queue_remove(id_queue))) { if (set_types(&avrule->stypes, id, &add, 0)) goto bad; } add = 1; while ((id = queue_remove(id_queue))) { if (set_types(&avrule->ttypes, id, &add, 0)) goto bad; } ebitmap_init(&tclasses); if (read_classes(&tclasses)) goto bad; id = (char *)queue_remove(id_queue); if (!id) { yyerror("no newtype?"); goto bad; } if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("type %s is not within scope", id); free(id); goto bad; } datum = (type_datum_t *) hashtab_search(policydbp->p_types.table, (hashtab_key_t) id); if (!datum || datum->flavor == TYPE_ATTRIB) { yyerror2("unknown type %s", id); goto bad; } ebitmap_for_each_bit(&tclasses, node, i) { if (ebitmap_node_get_bit(node, i)) { perm = malloc(sizeof(class_perm_node_t)); if (!perm) { yyerror("out of memory"); goto bad; } class_perm_node_init(perm); perm->class = i + 1; perm->data = datum->s.value; perm->next = avrule->perms; avrule->perms = perm; } } ebitmap_destroy(&tclasses); *rule = avrule; return 0; bad: avrule_destroy(avrule); free(avrule); return -1; } int define_compute_type(int which) { char *id; avrule_t *avrule; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); id = queue_remove(id_queue); free(id); return 0; } if (define_compute_type_helper(which, &avrule)) return -1; append_avrule(avrule); return 0; } avrule_t *define_cond_compute_type(int which) { char *id; avrule_t *avrule; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); id = queue_remove(id_queue); free(id); return (avrule_t *) 1; } if (define_compute_type_helper(which, &avrule)) return COND_ERR; return avrule; } int define_bool_tunable(int is_tunable) { char *id, *bool_value; cond_bool_datum_t *datum; int ret; uint32_t value; if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no identifier for bool definition?"); return -1; } if (id_has_dot(id)) { free(id); yyerror("boolean identifiers may not contain periods"); return -1; } datum = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t)); if (!datum) { yyerror("out of memory"); free(id); return -1; } memset(datum, 0, sizeof(cond_bool_datum_t)); if (is_tunable) datum->flags |= COND_BOOL_FLAGS_TUNABLE; ret = declare_symbol(SYM_BOOLS, id, datum, &value, &value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto cleanup; } case -2:{ yyerror2("duplicate declaration of boolean %s", id); goto cleanup; } case -1:{ yyerror("could not declare boolean here"); goto cleanup; } case 0: case 1:{ break; } default:{ assert(0); /* should never get here */ } } datum->s.value = value; bool_value = (char *)queue_remove(id_queue); if (!bool_value) { yyerror("no default value for bool definition?"); free(id); return -1; } datum->state = (int)(bool_value[0] == 'T') ? 1 : 0; return 0; cleanup: cond_destroy_bool(id, datum, NULL); return -1; } avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl) { if (pass == 1) { /* return something so we get through pass 1 */ return (avrule_t *) 1; } if (sl == NULL) { /* This is a require block, return previous list */ return avlist; } /* prepend the new avlist to the pre-existing one */ sl->next = avlist; return sl; } int define_te_avtab_helper(int which, avrule_t ** rule) { char *id; class_datum_t *cladatum; perm_datum_t *perdatum = NULL; class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL; ebitmap_t tclasses; ebitmap_node_t *node; avrule_t *avrule; unsigned int i; int add = 1, ret = 0; int suppress = 0; avrule = (avrule_t *) malloc(sizeof(avrule_t)); if (!avrule) { yyerror("memory error"); ret = -1; goto out; } avrule_init(avrule); avrule->specified = which; avrule->line = policydb_lineno; while ((id = queue_remove(id_queue))) { if (set_types (&avrule->stypes, id, &add, which == AVRULE_NEVERALLOW ? 1 : 0)) { ret = -1; goto out; } } add = 1; while ((id = queue_remove(id_queue))) { if (strcmp(id, "self") == 0) { free(id); avrule->flags |= RULE_SELF; continue; } if (set_types (&avrule->ttypes, id, &add, which == AVRULE_NEVERALLOW ? 1 : 0)) { ret = -1; goto out; } } ebitmap_init(&tclasses); ret = read_classes(&tclasses); if (ret) goto out; perms = NULL; ebitmap_for_each_bit(&tclasses, node, i) { if (!ebitmap_node_get_bit(node, i)) continue; cur_perms = (class_perm_node_t *) malloc(sizeof(class_perm_node_t)); if (!cur_perms) { yyerror("out of memory"); ret = -1; goto out; } class_perm_node_init(cur_perms); cur_perms->class = i + 1; if (!perms) perms = cur_perms; if (tail) tail->next = cur_perms; tail = cur_perms; } while ((id = queue_remove(id_queue))) { cur_perms = perms; ebitmap_for_each_bit(&tclasses, node, i) { if (!ebitmap_node_get_bit(node, i)) continue; cladatum = policydbp->class_val_to_struct[i]; if (strcmp(id, "*") == 0) { /* set all permissions in the class */ cur_perms->data = ~0U; goto next; } if (strcmp(id, "~") == 0) { /* complement the set */ if (which == AVRULE_DONTAUDIT) yywarn("dontaudit rule with a ~?"); cur_perms->data = ~cur_perms->data; goto next; } perdatum = hashtab_search(cladatum->permissions.table, id); if (!perdatum) { if (cladatum->comdatum) { perdatum = hashtab_search(cladatum->comdatum-> permissions.table, id); } } if (!perdatum) { if (!suppress) yyerror2("permission %s is not defined" " for class %s", id, policydbp->p_class_val_to_name[i]); continue; } else if (!is_perm_in_scope (id, policydbp->p_class_val_to_name[i])) { if (!suppress) { yyerror2("permission %s of class %s is" " not within scope", id, policydbp->p_class_val_to_name[i]); } continue; } else { cur_perms->data |= 1U << (perdatum->s.value - 1); } next: cur_perms = cur_perms->next; } free(id); } ebitmap_destroy(&tclasses); avrule->perms = perms; *rule = avrule; out: return ret; } avrule_t *define_cond_te_avtab(int which) { char *id; avrule_t *avrule; int i; if (pass == 1) { for (i = 0; i < 4; i++) { while ((id = queue_remove(id_queue))) free(id); } return (avrule_t *) 1; /* any non-NULL value */ } if (define_te_avtab_helper(which, &avrule)) return COND_ERR; return avrule; } int define_te_avtab(int which) { char *id; avrule_t *avrule; int i; if (pass == 1) { for (i = 0; i < 4; i++) { while ((id = queue_remove(id_queue))) free(id); } return 0; } if (define_te_avtab_helper(which, &avrule)) return -1; /* append this avrule to the end of the current rules list */ append_avrule(avrule); return 0; } /* The role-types rule is no longer used to declare regular role or * role attribute, but solely aimed for declaring role-types associations. */ int define_role_types(void) { role_datum_t *role; char *id; int add = 1; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no role name for role-types rule?"); return -1; } if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("role %s is not within scope", id); free(id); return -1; } role = hashtab_search(policydbp->p_roles.table, id); if (!role) { yyerror2("unknown role %s", id); free(id); return -1; } while ((id = queue_remove(id_queue))) { if (set_types(&role->types, id, &add, 0)) return -1; } return 0; } int define_attrib_role(void) { if (pass == 2) { free(queue_remove(id_queue)); return 0; } /* Declare a role attribute */ if (declare_role(TRUE) == NULL) return -1; return 0; } int define_role_attr(void) { char *id; role_datum_t *r, *attr; if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } /* Declare a regular role */ if ((r = declare_role(FALSE)) == NULL) return -1; while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("attribute %s is not within scope", id); free(id); return -1; } attr = hashtab_search(policydbp->p_roles.table, id); if (!attr) { /* treat it as a fatal error */ yyerror2("role attribute %s is not declared", id); free(id); return -1; } if (attr->flavor != ROLE_ATTRIB) { yyerror2("%s is a regular role, not an attribute", id); free(id); return -1; } if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) { yyerror("Out of memory!"); return -1; } if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) { yyerror("out of memory"); return -1; } } return 0; } int define_roleattribute(void) { char *id; role_datum_t *r, *attr; if (pass == 2) { while ((id = queue_remove(id_queue))) free(id); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no role name for roleattribute definition?"); return -1; } if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("role %s is not within scope", id); free(id); return -1; } r = hashtab_search(policydbp->p_roles.table, id); /* We support adding one role attribute into another */ if (!r) { yyerror2("unknown role %s", id); free(id); return -1; } while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("attribute %s is not within scope", id); free(id); return -1; } attr = hashtab_search(policydbp->p_roles.table, id); if (!attr) { /* treat it as a fatal error */ yyerror2("role attribute %s is not declared", id); free(id); return -1; } if (attr->flavor != ROLE_ATTRIB) { yyerror2("%s is a regular role, not an attribute", id); free(id); return -1; } if ((attr = get_local_role(id, attr->s.value, 1)) == NULL) { yyerror("Out of memory!"); return -1; } if (ebitmap_set_bit(&attr->roles, (r->s.value - 1), TRUE)) { yyerror("out of memory"); return -1; } } return 0; } role_datum_t *merge_roles_dom(role_datum_t * r1, role_datum_t * r2) { role_datum_t *new; if (pass == 1) { return (role_datum_t *) 1; /* any non-NULL value */ } new = malloc(sizeof(role_datum_t)); if (!new) { yyerror("out of memory"); return NULL; } memset(new, 0, sizeof(role_datum_t)); new->s.value = 0; /* temporary role */ if (ebitmap_or(&new->dominates, &r1->dominates, &r2->dominates)) { yyerror("out of memory"); free(new); return NULL; } if (ebitmap_or(&new->types.types, &r1->types.types, &r2->types.types)) { yyerror("out of memory"); free(new); return NULL; } if (!r1->s.value) { /* free intermediate result */ type_set_destroy(&r1->types); ebitmap_destroy(&r1->dominates); free(r1); } if (!r2->s.value) { /* free intermediate result */ yyerror("right hand role is temporary?"); type_set_destroy(&r2->types); ebitmap_destroy(&r2->dominates); free(r2); } return new; } /* This function eliminates the ordering dependency of role dominance rule */ static int dominate_role_recheck(hashtab_key_t key, hashtab_datum_t datum, void *arg) { role_datum_t *rdp = (role_datum_t *) arg; role_datum_t *rdatum = (role_datum_t *) datum; ebitmap_node_t *node; int i; /* Don't bother to process against self role */ if (rdatum->s.value == rdp->s.value) return 0; /* If a dominating role found */ if (ebitmap_get_bit(&(rdatum->dominates), rdp->s.value - 1)) { ebitmap_t types; ebitmap_init(&types); if (type_set_expand(&rdp->types, &types, policydbp, 1)) { ebitmap_destroy(&types); return -1; } /* raise types and dominates from dominated role */ ebitmap_for_each_bit(&rdp->dominates, node, i) { if (ebitmap_node_get_bit(node, i)) if (ebitmap_set_bit (&rdatum->dominates, i, TRUE)) goto oom; } ebitmap_for_each_bit(&types, node, i) { if (ebitmap_node_get_bit(node, i)) if (ebitmap_set_bit (&rdatum->types.types, i, TRUE)) goto oom; } ebitmap_destroy(&types); } /* go through all the roles */ return 0; oom: yyerror("Out of memory"); return -1; } role_datum_t *define_role_dom(role_datum_t * r) { role_datum_t *role; char *role_id; ebitmap_node_t *node; unsigned int i; int ret; if (pass == 1) { role_id = queue_remove(id_queue); free(role_id); return (role_datum_t *) 1; /* any non-NULL value */ } yywarn("Role dominance has been deprecated"); role_id = queue_remove(id_queue); if (!is_id_in_scope(SYM_ROLES, role_id)) { yyerror2("role %s is not within scope", role_id); free(role_id); return NULL; } role = (role_datum_t *) hashtab_search(policydbp->p_roles.table, role_id); if (!role) { role = (role_datum_t *) malloc(sizeof(role_datum_t)); if (!role) { yyerror("out of memory"); free(role_id); return NULL; } memset(role, 0, sizeof(role_datum_t)); ret = declare_symbol(SYM_ROLES, (hashtab_key_t) role_id, (hashtab_datum_t) role, &role->s.value, &role->s.value); switch (ret) { case -3:{ yyerror("Out of memory!"); goto cleanup; } case -2:{ yyerror2("duplicate declaration of role %s", role_id); goto cleanup; } case -1:{ yyerror("could not declare role here"); goto cleanup; } case 0: case 1:{ break; } default:{ assert(0); /* should never get here */ } } if (ebitmap_set_bit(&role->dominates, role->s.value - 1, TRUE)) { yyerror("Out of memory!"); goto cleanup; } } if (r) { ebitmap_t types; ebitmap_init(&types); ebitmap_for_each_bit(&r->dominates, node, i) { if (ebitmap_node_get_bit(node, i)) if (ebitmap_set_bit(&role->dominates, i, TRUE)) goto oom; } if (type_set_expand(&r->types, &types, policydbp, 1)) { ebitmap_destroy(&types); return NULL; } ebitmap_for_each_bit(&types, node, i) { if (ebitmap_node_get_bit(node, i)) if (ebitmap_set_bit (&role->types.types, i, TRUE)) goto oom; } ebitmap_destroy(&types); if (!r->s.value) { /* free intermediate result */ type_set_destroy(&r->types); ebitmap_destroy(&r->dominates); free(r); } /* * Now go through all the roles and escalate this role's * dominates and types if a role dominates this role. */ hashtab_map(policydbp->p_roles.table, dominate_role_recheck, role); } return role; cleanup: free(role_id); role_datum_destroy(role); free(role); return NULL; oom: yyerror("Out of memory"); goto cleanup; } static int role_val_to_name_helper(hashtab_key_t key, hashtab_datum_t datum, void *p) { struct val_to_name *v = p; role_datum_t *roldatum; roldatum = (role_datum_t *) datum; if (v->val == roldatum->s.value) { v->name = key; return 1; } return 0; } static char *role_val_to_name(unsigned int val) { struct val_to_name v; int rc; v.val = val; rc = hashtab_map(policydbp->p_roles.table, role_val_to_name_helper, &v); if (rc) return v.name; return NULL; } static int set_roles(role_set_t * set, char *id) { role_datum_t *r; if (strcmp(id, "*") == 0) { free(id); yyerror("* is not allowed for role sets"); return -1; } if (strcmp(id, "~") == 0) { free(id); yyerror("~ is not allowed for role sets"); return -1; } if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("role %s is not within scope", id); free(id); return -1; } r = hashtab_search(policydbp->p_roles.table, id); if (!r) { yyerror2("unknown role %s", id); free(id); return -1; } if (ebitmap_set_bit(&set->roles, r->s.value - 1, TRUE)) { yyerror("out of memory"); free(id); return -1; } free(id); return 0; } int define_role_trans(int class_specified) { char *id; role_datum_t *role; role_set_t roles; type_set_t types; class_datum_t *cladatum; ebitmap_t e_types, e_roles, e_classes; ebitmap_node_t *tnode, *rnode, *cnode; struct role_trans *tr = NULL; struct role_trans_rule *rule = NULL; unsigned int i, j, k; int add = 1; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); if (class_specified) while ((id = queue_remove(id_queue))) free(id); id = queue_remove(id_queue); free(id); return 0; } role_set_init(&roles); ebitmap_init(&e_roles); type_set_init(&types); ebitmap_init(&e_types); ebitmap_init(&e_classes); while ((id = queue_remove(id_queue))) { if (set_roles(&roles, id)) return -1; } add = 1; while ((id = queue_remove(id_queue))) { if (set_types(&types, id, &add, 0)) return -1; } if (class_specified) { if (read_classes(&e_classes)) return -1; } else { cladatum = hashtab_search(policydbp->p_classes.table, "process"); if (!cladatum) { yyerror2("could not find process class for " "legacy role_transition statement"); return -1; } if (ebitmap_set_bit(&e_classes, cladatum->s.value - 1, TRUE)) { yyerror("out of memory"); return -1; } } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no new role in transition definition?"); goto bad; } if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("role %s is not within scope", id); free(id); goto bad; } role = hashtab_search(policydbp->p_roles.table, id); if (!role) { yyerror2("unknown role %s used in transition definition", id); goto bad; } if (role->flavor != ROLE_ROLE) { yyerror2("the new role %s must be a regular role", id); goto bad; } /* This ebitmap business is just to ensure that there are not conflicting role_trans rules */ if (role_set_expand(&roles, &e_roles, policydbp, NULL, NULL)) goto bad; if (type_set_expand(&types, &e_types, policydbp, 1)) goto bad; ebitmap_for_each_bit(&e_roles, rnode, i) { if (!ebitmap_node_get_bit(rnode, i)) continue; ebitmap_for_each_bit(&e_types, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; ebitmap_for_each_bit(&e_classes, cnode, k) { if (!ebitmap_node_get_bit(cnode, k)) continue; for (tr = policydbp->role_tr; tr; tr = tr->next) { if (tr->role == (i + 1) && tr->type == (j + 1) && tr->tclass == (k + 1)) { yyerror2("duplicate role " "transition for " "(%s,%s,%s)", role_val_to_name(i+1), policydbp->p_type_val_to_name[j], policydbp->p_class_val_to_name[k]); goto bad; } } tr = malloc(sizeof(struct role_trans)); if (!tr) { yyerror("out of memory"); return -1; } memset(tr, 0, sizeof(struct role_trans)); tr->role = i + 1; tr->type = j + 1; tr->tclass = k + 1; tr->new_role = role->s.value; tr->next = policydbp->role_tr; policydbp->role_tr = tr; } } } /* Now add the real rule */ rule = malloc(sizeof(struct role_trans_rule)); if (!rule) { yyerror("out of memory"); return -1; } memset(rule, 0, sizeof(struct role_trans_rule)); rule->roles = roles; rule->types = types; rule->classes = e_classes; rule->new_role = role->s.value; append_role_trans(rule); ebitmap_destroy(&e_roles); ebitmap_destroy(&e_types); return 0; bad: return -1; } int define_role_allow(void) { char *id; struct role_allow_rule *ra = 0; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); return 0; } ra = malloc(sizeof(role_allow_rule_t)); if (!ra) { yyerror("out of memory"); return -1; } role_allow_rule_init(ra); while ((id = queue_remove(id_queue))) { if (set_roles(&ra->roles, id)) { free(ra); return -1; } } while ((id = queue_remove(id_queue))) { if (set_roles(&ra->new_roles, id)) { free(ra); return -1; } } append_role_allow(ra); return 0; } avrule_t *define_cond_filename_trans(void) { yyerror("type transitions with a filename not allowed inside " "conditionals\n"); return COND_ERR; } int define_filename_trans(void) { char *id, *name = NULL; type_set_t stypes, ttypes; ebitmap_t e_stypes, e_ttypes; ebitmap_t e_tclasses; ebitmap_node_t *snode, *tnode, *cnode; filename_trans_t *ft; filename_trans_rule_t *ftr; type_datum_t *typdatum; uint32_t otype; unsigned int c, s, t; int add; if (pass == 1) { /* stype */ while ((id = queue_remove(id_queue))) free(id); /* ttype */ while ((id = queue_remove(id_queue))) free(id); /* tclass */ while ((id = queue_remove(id_queue))) free(id); /* otype */ id = queue_remove(id_queue); free(id); /* name */ id = queue_remove(id_queue); free(id); return 0; } add = 1; type_set_init(&stypes); while ((id = queue_remove(id_queue))) { if (set_types(&stypes, id, &add, 0)) goto bad; } add =1; type_set_init(&ttypes); while ((id = queue_remove(id_queue))) { if (set_types(&ttypes, id, &add, 0)) goto bad; } ebitmap_init(&e_tclasses); if (read_classes(&e_tclasses)) goto bad; id = (char *)queue_remove(id_queue); if (!id) { yyerror("no otype in transition definition?"); goto bad; } if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("type %s is not within scope", id); free(id); goto bad; } typdatum = hashtab_search(policydbp->p_types.table, id); if (!typdatum) { yyerror2("unknown type %s used in transition definition", id); goto bad; } free(id); otype = typdatum->s.value; name = queue_remove(id_queue); if (!name) { yyerror("no pathname specified in filename_trans definition?"); goto bad; } /* We expand the class set into seperate rules. We expand the types * just to make sure there are not duplicates. They will get turned * into seperate rules later */ ebitmap_init(&e_stypes); if (type_set_expand(&stypes, &e_stypes, policydbp, 1)) goto bad; ebitmap_init(&e_ttypes); if (type_set_expand(&ttypes, &e_ttypes, policydbp, 1)) goto bad; ebitmap_for_each_bit(&e_tclasses, cnode, c) { if (!ebitmap_node_get_bit(cnode, c)) continue; ebitmap_for_each_bit(&e_stypes, snode, s) { if (!ebitmap_node_get_bit(snode, s)) continue; ebitmap_for_each_bit(&e_ttypes, tnode, t) { if (!ebitmap_node_get_bit(tnode, t)) continue; for (ft = policydbp->filename_trans; ft; ft = ft->next) { if (ft->stype == (s + 1) && ft->ttype == (t + 1) && ft->tclass == (c + 1) && !strcmp(ft->name, name)) { yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", name, policydbp->p_type_val_to_name[s], policydbp->p_type_val_to_name[t], policydbp->p_class_val_to_name[c]); goto bad; } } ft = malloc(sizeof(*ft)); if (!ft) { yyerror("out of memory"); goto bad; } memset(ft, 0, sizeof(*ft)); ft->next = policydbp->filename_trans; policydbp->filename_trans = ft; ft->name = strdup(name); if (!ft->name) { yyerror("out of memory"); goto bad; } ft->stype = s + 1; ft->ttype = t + 1; ft->tclass = c + 1; ft->otype = otype; } } /* Now add the real rule since we didn't find any duplicates */ ftr = malloc(sizeof(*ftr)); if (!ftr) { yyerror("out of memory"); goto bad; } filename_trans_rule_init(ftr); append_filename_trans(ftr); ftr->name = strdup(name); ftr->stypes = stypes; ftr->ttypes = ttypes; ftr->tclass = c + 1; ftr->otype = otype; } free(name); ebitmap_destroy(&e_stypes); ebitmap_destroy(&e_ttypes); ebitmap_destroy(&e_tclasses); return 0; bad: free(name); return -1; } static constraint_expr_t *constraint_expr_clone(constraint_expr_t * expr) { constraint_expr_t *h = NULL, *l = NULL, *e, *newe; for (e = expr; e; e = e->next) { newe = malloc(sizeof(*newe)); if (!newe) goto oom; if (constraint_expr_init(newe) == -1) { free(newe); goto oom; } if (l) l->next = newe; else h = newe; l = newe; newe->expr_type = e->expr_type; newe->attr = e->attr; newe->op = e->op; if (newe->expr_type == CEXPR_NAMES) { if (newe->attr & CEXPR_TYPE) { if (type_set_cpy (newe->type_names, e->type_names)) goto oom; } else { if (ebitmap_cpy(&newe->names, &e->names)) goto oom; } } } return h; oom: e = h; while (e) { l = e; e = e->next; constraint_expr_destroy(l); } return NULL; } int define_constraint(constraint_expr_t * expr) { struct constraint_node *node; char *id; class_datum_t *cladatum; perm_datum_t *perdatum; ebitmap_t classmap; ebitmap_node_t *enode; constraint_expr_t *e; unsigned int i; int depth; unsigned char useexpr = 1; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); return 0; } depth = -1; for (e = expr; e; e = e->next) { switch (e->expr_type) { case CEXPR_NOT: if (depth < 0) { yyerror("illegal constraint expression"); return -1; } break; case CEXPR_AND: case CEXPR_OR: if (depth < 1) { yyerror("illegal constraint expression"); return -1; } depth--; break; case CEXPR_ATTR: case CEXPR_NAMES: if (e->attr & CEXPR_XTARGET) { yyerror("illegal constraint expression"); return -1; /* only for validatetrans rules */ } if (depth == (CEXPR_MAXDEPTH - 1)) { yyerror("constraint expression is too deep"); return -1; } depth++; break; default: yyerror("illegal constraint expression"); return -1; } } if (depth != 0) { yyerror("illegal constraint expression"); return -1; } ebitmap_init(&classmap); while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); free(id); return -1; } cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, (hashtab_key_t) id); if (!cladatum) { yyerror2("class %s is not defined", id); ebitmap_destroy(&classmap); free(id); return -1; } if (ebitmap_set_bit(&classmap, cladatum->s.value - 1, TRUE)) { yyerror("out of memory"); ebitmap_destroy(&classmap); free(id); return -1; } node = malloc(sizeof(struct constraint_node)); if (!node) { yyerror("out of memory"); free(node); return -1; } memset(node, 0, sizeof(constraint_node_t)); if (useexpr) { node->expr = expr; useexpr = 0; } else { node->expr = constraint_expr_clone(expr); } if (!node->expr) { yyerror("out of memory"); free(node); return -1; } node->permissions = 0; node->next = cladatum->constraints; cladatum->constraints = node; free(id); } while ((id = queue_remove(id_queue))) { ebitmap_for_each_bit(&classmap, enode, i) { if (ebitmap_node_get_bit(enode, i)) { cladatum = policydbp->class_val_to_struct[i]; node = cladatum->constraints; perdatum = (perm_datum_t *) hashtab_search(cladatum-> permissions. table, (hashtab_key_t) id); if (!perdatum) { if (cladatum->comdatum) { perdatum = (perm_datum_t *) hashtab_search(cladatum-> comdatum-> permissions. table, (hashtab_key_t) id); } if (!perdatum) { yyerror2("permission %s is not" " defined", id); free(id); ebitmap_destroy(&classmap); return -1; } } node->permissions |= (1 << (perdatum->s.value - 1)); } } free(id); } ebitmap_destroy(&classmap); return 0; } int define_validatetrans(constraint_expr_t * expr) { struct constraint_node *node; char *id; class_datum_t *cladatum; ebitmap_t classmap; constraint_expr_t *e; int depth; unsigned char useexpr = 1; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); return 0; } depth = -1; for (e = expr; e; e = e->next) { switch (e->expr_type) { case CEXPR_NOT: if (depth < 0) { yyerror("illegal validatetrans expression"); return -1; } break; case CEXPR_AND: case CEXPR_OR: if (depth < 1) { yyerror("illegal validatetrans expression"); return -1; } depth--; break; case CEXPR_ATTR: case CEXPR_NAMES: if (depth == (CEXPR_MAXDEPTH - 1)) { yyerror("validatetrans expression is too deep"); return -1; } depth++; break; default: yyerror("illegal validatetrans expression"); return -1; } } if (depth != 0) { yyerror("illegal validatetrans expression"); return -1; } ebitmap_init(&classmap); while ((id = queue_remove(id_queue))) { if (!is_id_in_scope(SYM_CLASSES, id)) { yyerror2("class %s is not within scope", id); free(id); return -1; } cladatum = (class_datum_t *) hashtab_search(policydbp->p_classes.table, (hashtab_key_t) id); if (!cladatum) { yyerror2("class %s is not defined", id); ebitmap_destroy(&classmap); free(id); return -1; } if (ebitmap_set_bit(&classmap, (cladatum->s.value - 1), TRUE)) { yyerror("out of memory"); ebitmap_destroy(&classmap); free(id); return -1; } node = malloc(sizeof(struct constraint_node)); if (!node) { yyerror("out of memory"); return -1; } memset(node, 0, sizeof(constraint_node_t)); if (useexpr) { node->expr = expr; useexpr = 0; } else { node->expr = constraint_expr_clone(expr); } node->permissions = 0; node->next = cladatum->validatetrans; cladatum->validatetrans = node; free(id); } ebitmap_destroy(&classmap); return 0; } uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2) { struct constraint_expr *expr, *e1 = NULL, *e2; user_datum_t *user; role_datum_t *role; ebitmap_t negset; char *id; uint32_t val; int add = 1; if (pass == 1) { if (expr_type == CEXPR_NAMES) { while ((id = queue_remove(id_queue))) free(id); } return 1; /* any non-NULL value */ } if ((expr = malloc(sizeof(*expr))) == NULL || constraint_expr_init(expr) == -1) { yyerror("out of memory"); free(expr); return 0; } expr->expr_type = expr_type; switch (expr_type) { case CEXPR_NOT: e1 = NULL; e2 = (struct constraint_expr *)arg1; while (e2) { e1 = e2; e2 = e2->next; } if (!e1 || e1->next) { yyerror("illegal constraint expression"); constraint_expr_destroy(expr); return 0; } e1->next = expr; return arg1; case CEXPR_AND: case CEXPR_OR: e1 = NULL; e2 = (struct constraint_expr *)arg1; while (e2) { e1 = e2; e2 = e2->next; } if (!e1 || e1->next) { yyerror("illegal constraint expression"); constraint_expr_destroy(expr); return 0; } e1->next = (struct constraint_expr *)arg2; e1 = NULL; e2 = (struct constraint_expr *)arg2; while (e2) { e1 = e2; e2 = e2->next; } if (!e1 || e1->next) { yyerror("illegal constraint expression"); constraint_expr_destroy(expr); return 0; } e1->next = expr; return arg1; case CEXPR_ATTR: expr->attr = arg1; expr->op = arg2; return (uintptr_t) expr; case CEXPR_NAMES: add = 1; expr->attr = arg1; expr->op = arg2; ebitmap_init(&negset); while ((id = (char *)queue_remove(id_queue))) { if (expr->attr & CEXPR_USER) { if (!is_id_in_scope(SYM_USERS, id)) { yyerror2("user %s is not within scope", id); constraint_expr_destroy(expr); return 0; } user = (user_datum_t *) hashtab_search(policydbp-> p_users. table, (hashtab_key_t) id); if (!user) { yyerror2("unknown user %s", id); constraint_expr_destroy(expr); return 0; } val = user->s.value; } else if (expr->attr & CEXPR_ROLE) { if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("role %s is not within scope", id); constraint_expr_destroy(expr); return 0; } role = (role_datum_t *) hashtab_search(policydbp-> p_roles. table, (hashtab_key_t) id); if (!role) { yyerror2("unknown role %s", id); constraint_expr_destroy(expr); return 0; } val = role->s.value; } else if (expr->attr & CEXPR_TYPE) { if (set_types(expr->type_names, id, &add, 0)) { constraint_expr_destroy(expr); return 0; } continue; } else { yyerror("invalid constraint expression"); constraint_expr_destroy(expr); return 0; } if (ebitmap_set_bit(&expr->names, val - 1, TRUE)) { yyerror("out of memory"); ebitmap_destroy(&expr->names); constraint_expr_destroy(expr); return 0; } free(id); } ebitmap_destroy(&negset); return (uintptr_t) expr; default: break; } yyerror("invalid constraint expression"); constraint_expr_destroy(expr); return 0; } int define_conditional(cond_expr_t * expr, avrule_t * t, avrule_t * f) { cond_expr_t *e; int depth; cond_node_t cn, *cn_old; /* expression cannot be NULL */ if (!expr) { yyerror("illegal conditional expression"); return -1; } if (!t) { if (!f) { /* empty is fine, destroy expression and return */ cond_expr_destroy(expr); return 0; } /* Invert */ t = f; f = 0; expr = define_cond_expr(COND_NOT, expr, 0); if (!expr) { yyerror("unable to invert"); return -1; } } /* verify expression */ depth = -1; for (e = expr; e; e = e->next) { switch (e->expr_type) { case COND_NOT: if (depth < 0) { yyerror ("illegal conditional expression; Bad NOT"); return -1; } break; case COND_AND: case COND_OR: case COND_XOR: case COND_EQ: case COND_NEQ: if (depth < 1) { yyerror ("illegal conditional expression; Bad binary op"); return -1; } depth--; break; case COND_BOOL: if (depth == (COND_EXPR_MAXDEPTH - 1)) { yyerror ("conditional expression is like totally too deep"); return -1; } depth++; break; default: yyerror("illegal conditional expression"); return -1; } } if (depth != 0) { yyerror("illegal conditional expression"); return -1; } /* use tmp conditional node to partially build new node */ memset(&cn, 0, sizeof(cn)); cn.expr = expr; cn.avtrue_list = t; cn.avfalse_list = f; /* normalize/precompute expression */ if (cond_normalize_expr(policydbp, &cn) < 0) { yyerror("problem normalizing conditional expression"); return -1; } /* get the existing conditional node, or create a new one */ cn_old = get_current_cond_list(&cn); if (!cn_old) { return -1; } append_cond_list(&cn); /* note that there is no check here for duplicate rules, nor * check that rule already exists in base -- that will be * handled during conditional expansion, in expand.c */ cn.avtrue_list = NULL; cn.avfalse_list = NULL; cond_node_destroy(&cn); return 0; } cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void *arg2) { struct cond_expr *expr, *e1 = NULL, *e2; cond_bool_datum_t *bool_var; char *id; /* expressions are handled in the second pass */ if (pass == 1) { if (expr_type == COND_BOOL) { while ((id = queue_remove(id_queue))) { free(id); } } return (cond_expr_t *) 1; /* any non-NULL value */ } /* create a new expression struct */ expr = malloc(sizeof(struct cond_expr)); if (!expr) { yyerror("out of memory"); return NULL; } memset(expr, 0, sizeof(cond_expr_t)); expr->expr_type = expr_type; /* create the type asked for */ switch (expr_type) { case COND_NOT: e1 = NULL; e2 = (struct cond_expr *)arg1; while (e2) { e1 = e2; e2 = e2->next; } if (!e1 || e1->next) { yyerror("illegal conditional NOT expression"); free(expr); return NULL; } e1->next = expr; return (struct cond_expr *)arg1; case COND_AND: case COND_OR: case COND_XOR: case COND_EQ: case COND_NEQ: e1 = NULL; e2 = (struct cond_expr *)arg1; while (e2) { e1 = e2; e2 = e2->next; } if (!e1 || e1->next) { yyerror ("illegal left side of conditional binary op expression"); free(expr); return NULL; } e1->next = (struct cond_expr *)arg2; e1 = NULL; e2 = (struct cond_expr *)arg2; while (e2) { e1 = e2; e2 = e2->next; } if (!e1 || e1->next) { yyerror ("illegal right side of conditional binary op expression"); free(expr); return NULL; } e1->next = expr; return (struct cond_expr *)arg1; case COND_BOOL: id = (char *)queue_remove(id_queue); if (!id) { yyerror("bad conditional; expected boolean id"); free(id); free(expr); return NULL; } if (!is_id_in_scope(SYM_BOOLS, id)) { yyerror2("boolean %s is not within scope", id); free(id); free(expr); return NULL; } bool_var = (cond_bool_datum_t *) hashtab_search(policydbp->p_bools. table, (hashtab_key_t) id); if (!bool_var) { yyerror2("unknown boolean %s in conditional expression", id); free(expr); free(id); return NULL; } expr->bool = bool_var->s.value; free(id); return expr; default: yyerror("illegal conditional expression"); free(expr); return NULL; } } static int set_user_roles(role_set_t * set, char *id) { role_datum_t *r; unsigned int i; ebitmap_node_t *node; if (strcmp(id, "*") == 0) { free(id); yyerror("* is not allowed in user declarations"); return -1; } if (strcmp(id, "~") == 0) { free(id); yyerror("~ is not allowed in user declarations"); return -1; } if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("role %s is not within scope", id); free(id); return -1; } r = hashtab_search(policydbp->p_roles.table, id); if (!r) { yyerror2("unknown role %s", id); free(id); return -1; } /* set the role and every role it dominates */ ebitmap_for_each_bit(&r->dominates, node, i) { if (ebitmap_node_get_bit(node, i)) if (ebitmap_set_bit(&set->roles, i, TRUE)) goto oom; } free(id); return 0; oom: yyerror("out of memory"); return -1; } static int parse_categories(char *id, level_datum_t * levdatum, ebitmap_t * cats) { cat_datum_t *cdatum; int range_start, range_end, i; if (id_has_dot(id)) { char *id_start = id; char *id_end = strchr(id, '.'); *(id_end++) = '\0'; cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id_start); if (!cdatum) { yyerror2("unknown category %s", id_start); return -1; } range_start = cdatum->s.value - 1; cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id_end); if (!cdatum) { yyerror2("unknown category %s", id_end); return -1; } range_end = cdatum->s.value - 1; if (range_end < range_start) { yyerror2("category range is invalid"); return -1; } } else { cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id); if (!cdatum) { yyerror2("unknown category %s", id); return -1; } range_start = range_end = cdatum->s.value - 1; } for (i = range_start; i <= range_end; i++) { if (!ebitmap_get_bit(&levdatum->level->cat, i)) { uint32_t level_value = levdatum->level->sens - 1; policydb_index_others(NULL, policydbp, 0); yyerror2("category %s can not be associated " "with level %s", policydbp->p_cat_val_to_name[i], policydbp->p_sens_val_to_name[level_value]); return -1; } if (ebitmap_set_bit(cats, i, TRUE)) { yyerror("out of memory"); return -1; } } return 0; } static int parse_semantic_categories(char *id, level_datum_t * levdatum, mls_semantic_cat_t ** cats) { cat_datum_t *cdatum; mls_semantic_cat_t *newcat; unsigned int range_start, range_end; if (id_has_dot(id)) { char *id_start = id; char *id_end = strchr(id, '.'); *(id_end++) = '\0'; cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id_start); if (!cdatum) { yyerror2("unknown category %s", id_start); return -1; } range_start = cdatum->s.value; cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id_end); if (!cdatum) { yyerror2("unknown category %s", id_end); return -1; } range_end = cdatum->s.value; } else { cdatum = (cat_datum_t *) hashtab_search(policydbp->p_cats.table, (hashtab_key_t) id); if (!cdatum) { yyerror2("unknown category %s", id); return -1; } range_start = range_end = cdatum->s.value; } newcat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); if (!newcat) { yyerror("out of memory"); return -1; } mls_semantic_cat_init(newcat); newcat->next = *cats; newcat->low = range_start; newcat->high = range_end; *cats = newcat; return 0; } int define_user(void) { char *id; user_datum_t *usrdatum; level_datum_t *levdatum; int l; if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); if (mlspol) { while ((id = queue_remove(id_queue))) free(id); id = queue_remove(id_queue); free(id); for (l = 0; l < 2; l++) { while ((id = queue_remove(id_queue))) { free(id); } id = queue_remove(id_queue); if (!id) break; free(id); } } return 0; } if ((usrdatum = declare_user()) == NULL) { return -1; } while ((id = queue_remove(id_queue))) { if (set_user_roles(&usrdatum->roles, id)) continue; } if (mlspol) { id = queue_remove(id_queue); if (!id) { yyerror("no default level specified for user"); return -1; } levdatum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id); if (!levdatum) { yyerror2("unknown sensitivity %s used in user" " level definition", id); free(id); return -1; } free(id); usrdatum->dfltlevel.sens = levdatum->level->sens; while ((id = queue_remove(id_queue))) { if (parse_semantic_categories(id, levdatum, &usrdatum->dfltlevel.cat)) { free(id); return -1; } free(id); } id = queue_remove(id_queue); for (l = 0; l < 2; l++) { levdatum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id); if (!levdatum) { yyerror2("unknown sensitivity %s used in user" " range definition", id); free(id); return -1; } free(id); usrdatum->range.level[l].sens = levdatum->level->sens; while ((id = queue_remove(id_queue))) { if (parse_semantic_categories(id, levdatum, &usrdatum->range.level[l].cat)) { free(id); return -1; } free(id); } id = queue_remove(id_queue); if (!id) break; } if (l == 0) { if (mls_semantic_level_cpy(&usrdatum->range.level[1], &usrdatum->range.level[0])) { yyerror("out of memory"); return -1; } } } return 0; } static int parse_security_context(context_struct_t * c) { char *id; role_datum_t *role; type_datum_t *typdatum; user_datum_t *usrdatum; level_datum_t *levdatum; int l; if (pass == 1) { id = queue_remove(id_queue); free(id); /* user */ id = queue_remove(id_queue); free(id); /* role */ id = queue_remove(id_queue); free(id); /* type */ if (mlspol) { id = queue_remove(id_queue); free(id); for (l = 0; l < 2; l++) { while ((id = queue_remove(id_queue))) { free(id); } id = queue_remove(id_queue); if (!id) break; free(id); } } return 0; } /* check context c to make sure ok to dereference c later */ if (c == NULL) { yyerror("null context pointer!"); return -1; } context_init(c); /* extract the user */ id = queue_remove(id_queue); if (!id) { yyerror("no effective user?"); goto bad; } if (!is_id_in_scope(SYM_USERS, id)) { yyerror2("user %s is not within scope", id); free(id); goto bad; } usrdatum = (user_datum_t *) hashtab_search(policydbp->p_users.table, (hashtab_key_t) id); if (!usrdatum) { yyerror2("user %s is not defined", id); free(id); goto bad; } c->user = usrdatum->s.value; /* no need to keep the user name */ free(id); /* extract the role */ id = (char *)queue_remove(id_queue); if (!id) { yyerror("no role name for sid context definition?"); return -1; } if (!is_id_in_scope(SYM_ROLES, id)) { yyerror2("role %s is not within scope", id); free(id); return -1; } role = (role_datum_t *) hashtab_search(policydbp->p_roles.table, (hashtab_key_t) id); if (!role) { yyerror2("role %s is not defined", id); free(id); return -1; } c->role = role->s.value; /* no need to keep the role name */ free(id); /* extract the type */ id = (char *)queue_remove(id_queue); if (!id) { yyerror("no type name for sid context definition?"); return -1; } if (!is_id_in_scope(SYM_TYPES, id)) { yyerror2("type %s is not within scope", id); free(id); return -1; } typdatum = (type_datum_t *) hashtab_search(policydbp->p_types.table, (hashtab_key_t) id); if (!typdatum || typdatum->flavor == TYPE_ATTRIB) { yyerror2("type %s is not defined or is an attribute", id); free(id); return -1; } c->type = typdatum->s.value; /* no need to keep the type name */ free(id); if (mlspol) { /* extract the low sensitivity */ id = (char *)queue_head(id_queue); if (!id) { yyerror("no sensitivity name for sid context" " definition?"); return -1; } id = (char *)queue_remove(id_queue); for (l = 0; l < 2; l++) { levdatum = (level_datum_t *) hashtab_search(policydbp->p_levels.table, (hashtab_key_t) id); if (!levdatum) { yyerror2("Sensitivity %s is not defined", id); free(id); return -1; } free(id); c->range.level[l].sens = levdatum->level->sens; /* extract low category set */ while ((id = queue_remove(id_queue))) { if (parse_categories(id, levdatum, &c->range.level[l].cat)) { free(id); return -1; } free(id); } /* extract high sensitivity */ id = (char *)queue_remove(id_queue); if (!id) break; } if (l == 0) { c->range.level[1].sens = c->range.level[0].sens; if (ebitmap_cpy(&c->range.level[1].cat, &c->range.level[0].cat)) { yyerror("out of memory"); goto bad; } } } if (!policydb_context_isvalid(policydbp, c)) { yyerror("invalid security context"); goto bad; } return 0; bad: context_destroy(c); return -1; } int define_initial_sid_context(void) { char *id; ocontext_t *c, *head; if (pass == 1) { id = (char *)queue_remove(id_queue); free(id); parse_security_context(NULL); return 0; } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no sid name for SID context definition?"); return -1; } head = policydbp->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { if (!strcmp(id, c->u.name)) break; } if (!c) { yyerror2("SID %s is not defined", id); free(id); return -1; } if (c->context[0].user) { yyerror2("The context for SID %s is multiply defined", id); free(id); return -1; } /* no need to keep the sid name */ free(id); if (parse_security_context(&c->context[0])) return -1; return 0; } int define_fs_context(unsigned int major, unsigned int minor) { ocontext_t *newc, *c, *head; if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { yyerror("fscon not supported for target"); return -1; } if (pass == 1) { parse_security_context(NULL); parse_security_context(NULL); return 0; } newc = (ocontext_t *) malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.name = (char *)malloc(6); if (!newc->u.name) { yyerror("out of memory"); free(newc); return -1; } sprintf(newc->u.name, "%02x:%02x", major, minor); if (parse_security_context(&newc->context[0])) { free(newc->u.name); free(newc); return -1; } if (parse_security_context(&newc->context[1])) { context_destroy(&newc->context[0]); free(newc->u.name); free(newc); return -1; } head = policydbp->ocontexts[OCON_FS]; for (c = head; c; c = c->next) { if (!strcmp(newc->u.name, c->u.name)) { yyerror2("duplicate entry for file system %s", newc->u.name); context_destroy(&newc->context[0]); context_destroy(&newc->context[1]); free(newc->u.name); free(newc); return -1; } } newc->next = head; policydbp->ocontexts[OCON_FS] = newc; return 0; } int define_pirq_context(unsigned int pirq) { ocontext_t *newc, *c, *l, *head; char *id; if (policydbp->target_platform != SEPOL_TARGET_XEN) { yyerror("pirqcon not supported for target"); return -1; } if (pass == 1) { id = (char *) queue_remove(id_queue); free(id); parse_security_context(NULL); return 0; } newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.pirq = pirq; if (parse_security_context(&newc->context[0])) { free(newc); return -1; } head = policydbp->ocontexts[OCON_XEN_PIRQ]; for (l = NULL, c = head; c; l = c, c = c->next) { unsigned int pirq2; pirq2 = c->u.pirq; if (pirq == pirq2) { yyerror2("duplicate pirqcon entry for %d ", pirq); goto bad; } } if (l) l->next = newc; else policydbp->ocontexts[OCON_XEN_PIRQ] = newc; return 0; bad: free(newc); return -1; } int define_iomem_context(unsigned long low, unsigned long high) { ocontext_t *newc, *c, *l, *head; char *id; if (policydbp->target_platform != SEPOL_TARGET_XEN) { yyerror("iomemcon not supported for target"); return -1; } if (pass == 1) { id = (char *)queue_remove(id_queue); free(id); parse_security_context(NULL); return 0; } newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.iomem.low_iomem = low; newc->u.iomem.high_iomem = high; if (low > high) { yyerror2("low memory 0x%x exceeds high memory 0x%x", low, high); free(newc); return -1; } if (parse_security_context(&newc->context[0])) { free(newc); return -1; } head = policydbp->ocontexts[OCON_XEN_IOMEM]; for (l = NULL, c = head; c; l = c, c = c->next) { unsigned int low2, high2; low2 = c->u.iomem.low_iomem; high2 = c->u.iomem.high_iomem; if (low <= high2 && low2 <= high) { yyerror2("iomemcon entry for 0x%x-0x%x overlaps with " "earlier entry 0x%x-0x%x", low, high, low2, high2); goto bad; } } if (l) l->next = newc; else policydbp->ocontexts[OCON_XEN_IOMEM] = newc; return 0; bad: free(newc); return -1; } int define_ioport_context(unsigned long low, unsigned long high) { ocontext_t *newc, *c, *l, *head; char *id; if (policydbp->target_platform != SEPOL_TARGET_XEN) { yyerror("ioportcon not supported for target"); return -1; } if (pass == 1) { id = (char *)queue_remove(id_queue); free(id); parse_security_context(NULL); return 0; } newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.ioport.low_ioport = low; newc->u.ioport.high_ioport = high; if (low > high) { yyerror2("low ioport 0x%x exceeds high ioport 0x%x", low, high); free(newc); return -1; } if (parse_security_context(&newc->context[0])) { free(newc); return -1; } head = policydbp->ocontexts[OCON_XEN_IOPORT]; for (l = NULL, c = head; c; l = c, c = c->next) { unsigned int low2, high2; low2 = c->u.ioport.low_ioport; high2 = c->u.ioport.high_ioport; if (low <= high2 && low2 <= high) { yyerror2("ioportcon entry for 0x%x-0x%x overlaps with" "earlier entry 0x%x-0x%x", low, high, low2, high2); goto bad; } } if (l) l->next = newc; else policydbp->ocontexts[OCON_XEN_IOPORT] = newc; return 0; bad: free(newc); return -1; } int define_pcidevice_context(unsigned long device) { ocontext_t *newc, *c, *l, *head; char *id; if (policydbp->target_platform != SEPOL_TARGET_XEN) { yyerror("pcidevicecon not supported for target"); return -1; } if (pass == 1) { id = (char *) queue_remove(id_queue); free(id); parse_security_context(NULL); return 0; } newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.device = device; if (parse_security_context(&newc->context[0])) { free(newc); return -1; } head = policydbp->ocontexts[OCON_XEN_PCIDEVICE]; for (l = NULL, c = head; c; l = c, c = c->next) { unsigned int device2; device2 = c->u.device; if (device == device2) { yyerror2("duplicate pcidevicecon entry for 0x%x ", device); goto bad; } } if (l) l->next = newc; else policydbp->ocontexts[OCON_XEN_PCIDEVICE] = newc; return 0; bad: free(newc); return -1; } int define_port_context(unsigned int low, unsigned int high) { ocontext_t *newc, *c, *l, *head; unsigned int protocol; char *id; if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { yyerror("portcon not supported for target"); return -1; } if (pass == 1) { id = (char *)queue_remove(id_queue); free(id); parse_security_context(NULL); return 0; } newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); id = (char *)queue_remove(id_queue); if (!id) { free(newc); return -1; } if ((strcmp(id, "tcp") == 0) || (strcmp(id, "TCP") == 0)) { protocol = IPPROTO_TCP; } else if ((strcmp(id, "udp") == 0) || (strcmp(id, "UDP") == 0)) { protocol = IPPROTO_UDP; } else { yyerror2("unrecognized protocol %s", id); free(newc); return -1; } newc->u.port.protocol = protocol; newc->u.port.low_port = low; newc->u.port.high_port = high; if (low > high) { yyerror2("low port %d exceeds high port %d", low, high); free(newc); return -1; } if (parse_security_context(&newc->context[0])) { free(newc); return -1; } /* Preserve the matching order specified in the configuration. */ head = policydbp->ocontexts[OCON_PORT]; for (l = NULL, c = head; c; l = c, c = c->next) { unsigned int prot2, low2, high2; prot2 = c->u.port.protocol; low2 = c->u.port.low_port; high2 = c->u.port.high_port; if (protocol != prot2) continue; if (low == low2 && high == high2) { yyerror2("duplicate portcon entry for %s %d-%d ", id, low, high); goto bad; } if (low2 <= low && high2 >= high) { yyerror2("portcon entry for %s %d-%d hidden by earlier " "entry for %d-%d", id, low, high, low2, high2); goto bad; } } if (l) l->next = newc; else policydbp->ocontexts[OCON_PORT] = newc; return 0; bad: free(newc); return -1; } int define_netif_context(void) { ocontext_t *newc, *c, *head; if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { yyerror("netifcon not supported for target"); return -1; } if (pass == 1) { free(queue_remove(id_queue)); parse_security_context(NULL); parse_security_context(NULL); return 0; } newc = (ocontext_t *) malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.name = (char *)queue_remove(id_queue); if (!newc->u.name) { free(newc); return -1; } if (parse_security_context(&newc->context[0])) { free(newc->u.name); free(newc); return -1; } if (parse_security_context(&newc->context[1])) { context_destroy(&newc->context[0]); free(newc->u.name); free(newc); return -1; } head = policydbp->ocontexts[OCON_NETIF]; for (c = head; c; c = c->next) { if (!strcmp(newc->u.name, c->u.name)) { yyerror2("duplicate entry for network interface %s", newc->u.name); context_destroy(&newc->context[0]); context_destroy(&newc->context[1]); free(newc->u.name); free(newc); return -1; } } newc->next = head; policydbp->ocontexts[OCON_NETIF] = newc; return 0; } int define_ipv4_node_context() { char *id; int rc = 0; struct in_addr addr, mask; ocontext_t *newc, *c, *l, *head; if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { yyerror("nodecon not supported for target"); return -1; } if (pass == 1) { free(queue_remove(id_queue)); free(queue_remove(id_queue)); parse_security_context(NULL); goto out; } id = queue_remove(id_queue); if (!id) { yyerror("failed to read ipv4 address"); rc = -1; goto out; } rc = inet_pton(AF_INET, id, &addr); free(id); if (rc < 1) { yyerror("failed to parse ipv4 address"); if (rc == 0) rc = -1; goto out; } id = queue_remove(id_queue); if (!id) { yyerror("failed to read ipv4 address"); rc = -1; goto out; } rc = inet_pton(AF_INET, id, &mask); free(id); if (rc < 1) { yyerror("failed to parse ipv4 mask"); if (rc == 0) rc = -1; goto out; } newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); rc = -1; goto out; } memset(newc, 0, sizeof(ocontext_t)); newc->u.node.addr = addr.s_addr; newc->u.node.mask = mask.s_addr; if (parse_security_context(&newc->context[0])) { free(newc); return -1; } /* Create order of most specific to least retaining the order specified in the configuration. */ head = policydbp->ocontexts[OCON_NODE]; for (l = NULL, c = head; c; l = c, c = c->next) { if (newc->u.node.mask > c->u.node.mask) break; } newc->next = c; if (l) l->next = newc; else policydbp->ocontexts[OCON_NODE] = newc; rc = 0; out: return rc; } int define_ipv6_node_context(void) { char *id; int rc = 0; struct in6_addr addr, mask; ocontext_t *newc, *c, *l, *head; if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { yyerror("nodecon not supported for target"); return -1; } if (pass == 1) { free(queue_remove(id_queue)); free(queue_remove(id_queue)); parse_security_context(NULL); goto out; } id = queue_remove(id_queue); if (!id) { yyerror("failed to read ipv6 address"); rc = -1; goto out; } rc = inet_pton(AF_INET6, id, &addr); free(id); if (rc < 1) { yyerror("failed to parse ipv6 address"); if (rc == 0) rc = -1; goto out; } id = queue_remove(id_queue); if (!id) { yyerror("failed to read ipv6 address"); rc = -1; goto out; } rc = inet_pton(AF_INET6, id, &mask); free(id); if (rc < 1) { yyerror("failed to parse ipv6 mask"); if (rc == 0) rc = -1; goto out; } newc = malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); rc = -1; goto out; } memset(newc, 0, sizeof(ocontext_t)); #ifdef DARWIN memcpy(&newc->u.node6.addr[0], &addr.s6_addr[0], 16); memcpy(&newc->u.node6.mask[0], &mask.s6_addr[0], 16); #else memcpy(&newc->u.node6.addr[0], &addr.s6_addr32[0], 16); memcpy(&newc->u.node6.mask[0], &mask.s6_addr32[0], 16); #endif if (parse_security_context(&newc->context[0])) { free(newc); rc = -1; goto out; } /* Create order of most specific to least retaining the order specified in the configuration. */ head = policydbp->ocontexts[OCON_NODE6]; for (l = NULL, c = head; c; l = c, c = c->next) { if (memcmp(&newc->u.node6.mask, &c->u.node6.mask, 16) > 0) break; } newc->next = c; if (l) l->next = newc; else policydbp->ocontexts[OCON_NODE6] = newc; rc = 0; out: return rc; } int define_fs_use(int behavior) { ocontext_t *newc, *c, *head; if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { yyerror("fsuse not supported for target"); return -1; } if (pass == 1) { free(queue_remove(id_queue)); parse_security_context(NULL); return 0; } newc = (ocontext_t *) malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.name = (char *)queue_remove(id_queue); if (!newc->u.name) { free(newc); return -1; } newc->v.behavior = behavior; if (parse_security_context(&newc->context[0])) { free(newc->u.name); free(newc); return -1; } head = policydbp->ocontexts[OCON_FSUSE]; for (c = head; c; c = c->next) { if (!strcmp(newc->u.name, c->u.name)) { yyerror2("duplicate fs_use entry for filesystem type %s", newc->u.name); context_destroy(&newc->context[0]); free(newc->u.name); free(newc); return -1; } } newc->next = head; policydbp->ocontexts[OCON_FSUSE] = newc; return 0; } int define_genfs_context_helper(char *fstype, int has_type) { struct genfs *genfs_p, *genfs, *newgenfs; ocontext_t *newc, *c, *head, *p; char *type = NULL; int len, len2; if (policydbp->target_platform != SEPOL_TARGET_SELINUX) { yyerror("genfs not supported for target"); return -1; } if (pass == 1) { free(fstype); free(queue_remove(id_queue)); if (has_type) free(queue_remove(id_queue)); parse_security_context(NULL); return 0; } for (genfs_p = NULL, genfs = policydbp->genfs; genfs; genfs_p = genfs, genfs = genfs->next) { if (strcmp(fstype, genfs->fstype) <= 0) break; } if (!genfs || strcmp(fstype, genfs->fstype)) { newgenfs = malloc(sizeof(struct genfs)); if (!newgenfs) { yyerror("out of memory"); return -1; } memset(newgenfs, 0, sizeof(struct genfs)); newgenfs->fstype = fstype; newgenfs->next = genfs; if (genfs_p) genfs_p->next = newgenfs; else policydbp->genfs = newgenfs; genfs = newgenfs; } newc = (ocontext_t *) malloc(sizeof(ocontext_t)); if (!newc) { yyerror("out of memory"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.name = (char *)queue_remove(id_queue); if (!newc->u.name) goto fail; if (has_type) { type = (char *)queue_remove(id_queue); if (!type) goto fail; if (type[1] != 0) { yyerror2("invalid type %s", type); goto fail; } switch (type[0]) { case 'b': newc->v.sclass = SECCLASS_BLK_FILE; break; case 'c': newc->v.sclass = SECCLASS_CHR_FILE; break; case 'd': newc->v.sclass = SECCLASS_DIR; break; case 'p': newc->v.sclass = SECCLASS_FIFO_FILE; break; case 'l': newc->v.sclass = SECCLASS_LNK_FILE; break; case 's': newc->v.sclass = SECCLASS_SOCK_FILE; break; case '-': newc->v.sclass = SECCLASS_FILE; break; default: yyerror2("invalid type %s", type); goto fail; } } if (parse_security_context(&newc->context[0])) goto fail; head = genfs->head; for (p = NULL, c = head; c; p = c, c = c->next) { if (!strcmp(newc->u.name, c->u.name) && (!newc->v.sclass || !c->v.sclass || newc->v.sclass == c->v.sclass)) { yyerror2("duplicate entry for genfs entry (%s, %s)", fstype, newc->u.name); goto fail; } len = strlen(newc->u.name); len2 = strlen(c->u.name); if (len > len2) break; } newc->next = c; if (p) p->next = newc; else genfs->head = newc; return 0; fail: if (type) free(type); context_destroy(&newc->context[0]); if (fstype) free(fstype); if (newc->u.name) free(newc->u.name); free(newc); return -1; } int define_genfs_context(int has_type) { return define_genfs_context_helper(queue_remove(id_queue), has_type); } int define_range_trans(int class_specified) { char *id; level_datum_t *levdatum = 0; class_datum_t *cladatum; range_trans_rule_t *rule; int l, add = 1; if (!mlspol) { yyerror("range_transition rule in non-MLS configuration"); return -1; } if (pass == 1) { while ((id = queue_remove(id_queue))) free(id); while ((id = queue_remove(id_queue))) free(id); if (class_specified) while ((id = queue_remove(id_queue))) free(id); id = queue_remove(id_queue); free(id); for (l = 0; l < 2; l++) { while ((id = queue_remove(id_queue))) { free(id); } id = queue_remove(id_queue); if (!id) break; free(id); } return 0; } rule = malloc(sizeof(struct range_trans_rule)); if (!rule) { yyerror("out of memory"); return -1; } range_trans_rule_init(rule); while ((id = queue_remove(id_queue))) { if (set_types(&rule->stypes, id, &add, 0)) goto out; } add = 1; while ((id = queue_remove(id_queue))) { if (set_types(&rule->ttypes, id, &add, 0)) goto out; } if (class_specified) { if (read_classes(&rule->tclasses)) goto out; } else { cladatum = hashtab_search(policydbp->p_classes.table, "process"); if (!cladatum) { yyerror2("could not find process class for " "legacy range_transition statement"); goto out; } if (ebitmap_set_bit(&rule->tclasses, cladatum->s.value - 1, TRUE)) { yyerror("out of memory"); goto out; } } id = (char *)queue_remove(id_queue); if (!id) { yyerror("no range in range_transition definition?"); goto out; } for (l = 0; l < 2; l++) { levdatum = hashtab_search(policydbp->p_levels.table, id); if (!levdatum) { yyerror2("unknown level %s used in range_transition " "definition", id); free(id); goto out; } free(id); rule->trange.level[l].sens = levdatum->level->sens; while ((id = queue_remove(id_queue))) { if (parse_semantic_categories(id, levdatum, &rule->trange.level[l].cat)) { free(id); goto out; } free(id); } id = (char *)queue_remove(id_queue); if (!id) break; } if (l == 0) { if (mls_semantic_level_cpy(&rule->trange.level[1], &rule->trange.level[0])) { yyerror("out of memory"); goto out; } } append_range_trans(rule); return 0; out: range_trans_rule_destroy(rule); free(rule); return -1; } /* FLASK */ checkpolicy-2.2/policy_define.h000066400000000000000000000051511223423440700166370ustar00rootroot00000000000000/* Functions used to define policy grammar components. */ #ifndef _POLICY_DEFINE_H_ #define _POLICY_DEFINE_H_ /* * We need the following so we have a valid error return code in yacc * when we have a parse error for a conditional rule. We can't check * for NULL (ie 0) because that is a potentially valid return. */ #define COND_ERR ((avrule_t *)-1) #define TRUE 1 #define FALSE 0 avrule_t *define_cond_compute_type(int which); avrule_t *define_cond_pol_list(avrule_t *avlist, avrule_t *stmt); avrule_t *define_cond_te_avtab(int which); avrule_t *define_cond_filename_trans(void); cond_expr_t *define_cond_expr(uint32_t expr_type, void *arg1, void* arg2); int define_attrib(void); int define_attrib_role(void); int define_av_perms(int inherits); int define_bool_tunable(int is_tunable); int define_category(void); int define_class(void); int define_default_user(int which); int define_default_role(int which); int define_default_type(int which); int define_default_range(int which); int define_common_perms(void); int define_compute_type(int which); int define_conditional(cond_expr_t *expr, avrule_t *t_list, avrule_t *f_list ); int define_constraint(constraint_expr_t *expr); int define_dominance(void); int define_fs_context(unsigned int major, unsigned int minor); int define_fs_use(int behavior); int define_genfs_context(int has_type); int define_initial_sid_context(void); int define_initial_sid(void); int define_ipv4_node_context(void); int define_ipv6_node_context(void); int define_level(void); int define_netif_context(void); int define_permissive(void); int define_polcap(void); int define_port_context(unsigned int low, unsigned int high); int define_pirq_context(unsigned int pirq); int define_iomem_context(unsigned long low, unsigned long high); int define_ioport_context(unsigned long low, unsigned long high); int define_pcidevice_context(unsigned long device); int define_range_trans(int class_specified); int define_role_allow(void); int define_role_trans(int class_specified); int define_role_types(void); int define_role_attr(void); int define_roleattribute(void); int define_filename_trans(void); int define_sens(void); int define_te_avtab(int which); int define_typealias(void); int define_typeattribute(void); int define_typebounds(void); int define_type(int alias); int define_user(void); int define_validatetrans(constraint_expr_t *expr); int insert_id(char *id,int push); int insert_separator(int push); role_datum_t *define_role_dom(role_datum_t *r); role_datum_t *merge_roles_dom(role_datum_t *r1,role_datum_t *r2); uintptr_t define_cexpr(uint32_t expr_type, uintptr_t arg1, uintptr_t arg2); #endif /* _POLICY_DEFINE_H_ */ checkpolicy-2.2/policy_parse.y000066400000000000000000000746431223423440700165540ustar00rootroot00000000000000 /* * Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: David Caplan, * * Added conditional policy language extensions * * Updated: Joshua Brindle * Karl MacMillan * Jason Tang * * Added support for binary policy modules * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2008 Tresys Technology, LLC * Copyright (C) 2007 Red Hat Inc. * 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. */ /* FLASK */ %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "queue.h" #include "checkpolicy.h" #include "module_compiler.h" #include "policy_define.h" extern policydb_t *policydbp; extern unsigned int pass; extern char yytext[]; extern int yylex(void); extern int yywarn(char *msg); extern int yyerror(char *msg); typedef int (* require_func_t)(); %} %union { unsigned int val; uintptr_t valptr; void *ptr; require_func_t require_func; } %type cond_expr cond_expr_prim cond_pol_list cond_else %type cond_allow_def cond_auditallow_def cond_auditdeny_def cond_dontaudit_def %type cond_transition_def cond_te_avtab_def cond_rule_def %type role_def roles %type cexpr cexpr_prim op role_mls_op %type ipv4_addr_def number %type require_decl_def %token PATH %token FILENAME %token CLONE %token COMMON %token CLASS %token CONSTRAIN %token VALIDATETRANS %token INHERITS %token SID %token ROLE %token ROLEATTRIBUTE %token ATTRIBUTE_ROLE %token ROLES %token TYPEALIAS %token TYPEATTRIBUTE %token TYPEBOUNDS %token TYPE %token TYPES %token ALIAS %token ATTRIBUTE %token BOOL %token TUNABLE %token IF %token ELSE %token TYPE_TRANSITION %token TYPE_MEMBER %token TYPE_CHANGE %token ROLE_TRANSITION %token RANGE_TRANSITION %token SENSITIVITY %token DOMINANCE %token DOM DOMBY INCOMP %token CATEGORY %token LEVEL %token RANGE %token MLSCONSTRAIN %token MLSVALIDATETRANS %token USER %token NEVERALLOW %token ALLOW %token AUDITALLOW %token AUDITDENY %token DONTAUDIT %token SOURCE %token TARGET %token SAMEUSER %token FSCON PORTCON NETIFCON NODECON %token PIRQCON IOMEMCON IOPORTCON PCIDEVICECON %token FSUSEXATTR FSUSETASK FSUSETRANS %token GENFSCON %token U1 U2 U3 R1 R2 R3 T1 T2 T3 L1 L2 H1 H2 %token NOT AND OR XOR %token CTRUE CFALSE %token IDENTIFIER %token NUMBER %token EQUALS %token NOTEQUAL %token IPV4_ADDR %token IPV6_ADDR %token MODULE VERSION_IDENTIFIER REQUIRE OPTIONAL %token POLICYCAP %token PERMISSIVE %token FILESYSTEM %token DEFAULT_USER DEFAULT_ROLE DEFAULT_TYPE DEFAULT_RANGE %token LOW_HIGH LOW HIGH %left OR %left XOR %left AND %right NOT %left EQUALS NOTEQUAL %% policy : base_policy | module_policy ; base_policy : { if (define_policy(pass, 0) == -1) return -1; } classes initial_sids access_vectors { if (pass == 1) { if (policydb_index_classes(policydbp)) return -1; } else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1; }} opt_default_rules opt_mls te_rbac users opt_constraints { if (pass == 1) { if (policydb_index_bools(policydbp)) return -1;} else if (pass == 2) { if (policydb_index_others(NULL, policydbp, 0)) return -1;}} initial_sid_contexts opt_fs_contexts opt_fs_uses opt_genfs_contexts net_contexts opt_dev_contexts ; classes : class_def | classes class_def ; class_def : CLASS identifier {if (define_class()) return -1;} ; initial_sids : initial_sid_def | initial_sids initial_sid_def ; initial_sid_def : SID identifier {if (define_initial_sid()) return -1;} ; access_vectors : opt_common_perms av_perms ; opt_common_perms : common_perms | ; common_perms : common_perms_def | common_perms common_perms_def ; common_perms_def : COMMON identifier '{' identifier_list '}' {if (define_common_perms()) return -1;} ; av_perms : av_perms_def | av_perms av_perms_def ; av_perms_def : CLASS identifier '{' identifier_list '}' {if (define_av_perms(FALSE)) return -1;} | CLASS identifier INHERITS identifier {if (define_av_perms(TRUE)) return -1;} | CLASS identifier INHERITS identifier '{' identifier_list '}' {if (define_av_perms(TRUE)) return -1;} ; opt_default_rules : default_rules | ; default_rules : default_user_def | default_role_def | default_type_def | default_range_def | default_rules default_user_def | default_rules default_role_def | default_rules default_type_def | default_rules default_range_def ; default_user_def : DEFAULT_USER names SOURCE ';' {if (define_default_user(DEFAULT_SOURCE)) return -1; } | DEFAULT_USER names TARGET ';' {if (define_default_user(DEFAULT_TARGET)) return -1; } ; default_role_def : DEFAULT_ROLE names SOURCE ';' {if (define_default_role(DEFAULT_SOURCE)) return -1; } | DEFAULT_ROLE names TARGET ';' {if (define_default_role(DEFAULT_TARGET)) return -1; } ; default_type_def : DEFAULT_TYPE names SOURCE ';' {if (define_default_type(DEFAULT_SOURCE)) return -1; } | DEFAULT_TYPE names TARGET ';' {if (define_default_type(DEFAULT_TARGET)) return -1; } ; default_range_def : DEFAULT_RANGE names SOURCE LOW ';' {if (define_default_range(DEFAULT_SOURCE_LOW)) return -1; } | DEFAULT_RANGE names SOURCE HIGH ';' {if (define_default_range(DEFAULT_SOURCE_HIGH)) return -1; } | DEFAULT_RANGE names SOURCE LOW_HIGH ';' {if (define_default_range(DEFAULT_SOURCE_LOW_HIGH)) return -1; } | DEFAULT_RANGE names TARGET LOW ';' {if (define_default_range(DEFAULT_TARGET_LOW)) return -1; } | DEFAULT_RANGE names TARGET HIGH ';' {if (define_default_range(DEFAULT_TARGET_HIGH)) return -1; } | DEFAULT_RANGE names TARGET LOW_HIGH ';' {if (define_default_range(DEFAULT_TARGET_LOW_HIGH)) return -1; } ; opt_mls : mls | ; mls : sensitivities dominance opt_categories levels mlspolicy ; sensitivities : sensitivity_def | sensitivities sensitivity_def ; sensitivity_def : SENSITIVITY identifier alias_def ';' {if (define_sens()) return -1;} | SENSITIVITY identifier ';' {if (define_sens()) return -1;} ; alias_def : ALIAS names ; dominance : DOMINANCE identifier {if (define_dominance()) return -1;} | DOMINANCE '{' identifier_list '}' {if (define_dominance()) return -1;} ; opt_categories : categories | ; categories : category_def | categories category_def ; category_def : CATEGORY identifier alias_def ';' {if (define_category()) return -1;} | CATEGORY identifier ';' {if (define_category()) return -1;} ; levels : level_def | levels level_def ; level_def : LEVEL identifier ':' id_comma_list ';' {if (define_level()) return -1;} | LEVEL identifier ';' {if (define_level()) return -1;} ; mlspolicy : mlspolicy_decl | mlspolicy mlspolicy_decl ; mlspolicy_decl : mlsconstraint_def | mlsvalidatetrans_def ; mlsconstraint_def : MLSCONSTRAIN names names cexpr ';' { if (define_constraint((constraint_expr_t*)$4)) return -1; } ; mlsvalidatetrans_def : MLSVALIDATETRANS names cexpr ';' { if (define_validatetrans((constraint_expr_t*)$3)) return -1; } ; te_rbac : te_rbac_decl | te_rbac te_rbac_decl ; te_rbac_decl : te_decl | rbac_decl | cond_stmt_def | optional_block | policycap_def | ';' ; rbac_decl : attribute_role_def | role_type_def | role_dominance | role_trans_def | role_allow_def | roleattribute_def | role_attr_def ; te_decl : attribute_def | type_def | typealias_def | typeattribute_def | typebounds_def | bool_def | tunable_def | transition_def | range_trans_def | te_avtab_def | permissive_def ; attribute_def : ATTRIBUTE identifier ';' { if (define_attrib()) return -1;} ; type_def : TYPE identifier alias_def opt_attr_list ';' {if (define_type(1)) return -1;} | TYPE identifier opt_attr_list ';' {if (define_type(0)) return -1;} ; typealias_def : TYPEALIAS identifier alias_def ';' {if (define_typealias()) return -1;} ; typeattribute_def : TYPEATTRIBUTE identifier id_comma_list ';' {if (define_typeattribute()) return -1;} ; typebounds_def : TYPEBOUNDS identifier id_comma_list ';' {if (define_typebounds()) return -1;} ; opt_attr_list : ',' id_comma_list | ; bool_def : BOOL identifier bool_val ';' { if (define_bool_tunable(0)) return -1; } ; tunable_def : TUNABLE identifier bool_val ';' { if (define_bool_tunable(1)) return -1; } ; bool_val : CTRUE { if (insert_id("T",0)) return -1; } | CFALSE { if (insert_id("F",0)) return -1; } ; cond_stmt_def : IF cond_expr '{' cond_pol_list '}' cond_else { if (pass == 2) { if (define_conditional((cond_expr_t*)$2, (avrule_t*)$4, (avrule_t*)$6) < 0) return -1; }} ; cond_else : ELSE '{' cond_pol_list '}' { $$ = $3; } | /* empty */ { $$ = NULL; } cond_expr : '(' cond_expr ')' { $$ = $2;} | NOT cond_expr { $$ = define_cond_expr(COND_NOT, $2, 0); if ($$ == 0) return -1; } | cond_expr AND cond_expr { $$ = define_cond_expr(COND_AND, $1, $3); if ($$ == 0) return -1; } | cond_expr OR cond_expr { $$ = define_cond_expr(COND_OR, $1, $3); if ($$ == 0) return -1; } | cond_expr XOR cond_expr { $$ = define_cond_expr(COND_XOR, $1, $3); if ($$ == 0) return -1; } | cond_expr EQUALS cond_expr { $$ = define_cond_expr(COND_EQ, $1, $3); if ($$ == 0) return -1; } | cond_expr NOTEQUAL cond_expr { $$ = define_cond_expr(COND_NEQ, $1, $3); if ($$ == 0) return -1; } | cond_expr_prim { $$ = $1; } ; cond_expr_prim : identifier { $$ = define_cond_expr(COND_BOOL,0, 0); if ($$ == COND_ERR) return -1; } ; cond_pol_list : cond_pol_list cond_rule_def { $$ = define_cond_pol_list((avrule_t *)$1, (avrule_t *)$2); } | /* empty */ { $$ = NULL; } ; cond_rule_def : cond_transition_def { $$ = $1; } | cond_te_avtab_def { $$ = $1; } | require_block { $$ = NULL; } ; cond_transition_def : TYPE_TRANSITION names names ':' names identifier filename ';' { $$ = define_cond_filename_trans() ; if ($$ == COND_ERR) return -1;} | TYPE_TRANSITION names names ':' names identifier ';' { $$ = define_cond_compute_type(AVRULE_TRANSITION) ; if ($$ == COND_ERR) return -1;} | TYPE_MEMBER names names ':' names identifier ';' { $$ = define_cond_compute_type(AVRULE_MEMBER) ; if ($$ == COND_ERR) return -1;} | TYPE_CHANGE names names ':' names identifier ';' { $$ = define_cond_compute_type(AVRULE_CHANGE) ; if ($$ == COND_ERR) return -1;} ; cond_te_avtab_def : cond_allow_def { $$ = $1; } | cond_auditallow_def { $$ = $1; } | cond_auditdeny_def { $$ = $1; } | cond_dontaudit_def { $$ = $1; } ; cond_allow_def : ALLOW names names ':' names names ';' { $$ = define_cond_te_avtab(AVRULE_ALLOWED) ; if ($$ == COND_ERR) return -1; } ; cond_auditallow_def : AUDITALLOW names names ':' names names ';' { $$ = define_cond_te_avtab(AVRULE_AUDITALLOW) ; if ($$ == COND_ERR) return -1; } ; cond_auditdeny_def : AUDITDENY names names ':' names names ';' { $$ = define_cond_te_avtab(AVRULE_AUDITDENY) ; if ($$ == COND_ERR) return -1; } ; cond_dontaudit_def : DONTAUDIT names names ':' names names ';' { $$ = define_cond_te_avtab(AVRULE_DONTAUDIT); if ($$ == COND_ERR) return -1; } ; ; transition_def : TYPE_TRANSITION names names ':' names identifier filename ';' {if (define_filename_trans()) return -1; } | TYPE_TRANSITION names names ':' names identifier ';' {if (define_compute_type(AVRULE_TRANSITION)) return -1;} | TYPE_MEMBER names names ':' names identifier ';' {if (define_compute_type(AVRULE_MEMBER)) return -1;} | TYPE_CHANGE names names ':' names identifier ';' {if (define_compute_type(AVRULE_CHANGE)) return -1;} ; range_trans_def : RANGE_TRANSITION names names mls_range_def ';' { if (define_range_trans(0)) return -1; } | RANGE_TRANSITION names names ':' names mls_range_def ';' { if (define_range_trans(1)) return -1; } ; te_avtab_def : allow_def | auditallow_def | auditdeny_def | dontaudit_def | neverallow_def ; allow_def : ALLOW names names ':' names names ';' {if (define_te_avtab(AVRULE_ALLOWED)) return -1; } ; auditallow_def : AUDITALLOW names names ':' names names ';' {if (define_te_avtab(AVRULE_AUDITALLOW)) return -1; } ; auditdeny_def : AUDITDENY names names ':' names names ';' {if (define_te_avtab(AVRULE_AUDITDENY)) return -1; } ; dontaudit_def : DONTAUDIT names names ':' names names ';' {if (define_te_avtab(AVRULE_DONTAUDIT)) return -1; } ; neverallow_def : NEVERALLOW names names ':' names names ';' {if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; } ; attribute_role_def : ATTRIBUTE_ROLE identifier ';' {if (define_attrib_role()) return -1; } ; role_type_def : ROLE identifier TYPES names ';' {if (define_role_types()) return -1;} ; role_attr_def : ROLE identifier opt_attr_list ';' {if (define_role_attr()) return -1;} ; role_dominance : DOMINANCE '{' roles '}' ; role_trans_def : ROLE_TRANSITION names names identifier ';' {if (define_role_trans(0)) return -1; } | ROLE_TRANSITION names names ':' names identifier ';' {if (define_role_trans(1)) return -1;} ; role_allow_def : ALLOW names names ';' {if (define_role_allow()) return -1; } ; roles : role_def { $$ = $1; } | roles role_def { $$ = merge_roles_dom((role_datum_t*)$1, (role_datum_t*)$2); if ($$ == 0) return -1;} ; role_def : ROLE identifier_push ';' {$$ = define_role_dom(NULL); if ($$ == 0) return -1;} | ROLE identifier_push '{' roles '}' {$$ = define_role_dom((role_datum_t*)$4); if ($$ == 0) return -1;} ; roleattribute_def : ROLEATTRIBUTE identifier id_comma_list ';' {if (define_roleattribute()) return -1;} ; opt_constraints : constraints | ; constraints : constraint_decl | constraints constraint_decl ; constraint_decl : constraint_def | validatetrans_def ; constraint_def : CONSTRAIN names names cexpr ';' { if (define_constraint((constraint_expr_t*)$4)) return -1; } ; validatetrans_def : VALIDATETRANS names cexpr ';' { if (define_validatetrans((constraint_expr_t*)$3)) return -1; } ; cexpr : '(' cexpr ')' { $$ = $2; } | NOT cexpr { $$ = define_cexpr(CEXPR_NOT, $2, 0); if ($$ == 0) return -1; } | cexpr AND cexpr { $$ = define_cexpr(CEXPR_AND, $1, $3); if ($$ == 0) return -1; } | cexpr OR cexpr { $$ = define_cexpr(CEXPR_OR, $1, $3); if ($$ == 0) return -1; } | cexpr_prim { $$ = $1; } ; cexpr_prim : U1 op U2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_USER, $2); if ($$ == 0) return -1; } | R1 role_mls_op R2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_ROLE, $2); if ($$ == 0) return -1; } | T1 op T2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_TYPE, $2); if ($$ == 0) return -1; } | U1 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, CEXPR_USER, $2); if ($$ == 0) return -1; } | U2 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_USER | CEXPR_TARGET), $2); if ($$ == 0) return -1; } | U3 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_USER | CEXPR_XTARGET), $2); if ($$ == 0) return -1; } | R1 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, CEXPR_ROLE, $2); if ($$ == 0) return -1; } | R2 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_TARGET), $2); if ($$ == 0) return -1; } | R3 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_XTARGET), $2); if ($$ == 0) return -1; } | T1 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, CEXPR_TYPE, $2); if ($$ == 0) return -1; } | T2 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_TARGET), $2); if ($$ == 0) return -1; } | T3 op { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_XTARGET), $2); if ($$ == 0) return -1; } | SAMEUSER { $$ = define_cexpr(CEXPR_ATTR, CEXPR_USER, CEXPR_EQ); if ($$ == 0) return -1; } | SOURCE ROLE { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, CEXPR_ROLE, CEXPR_EQ); if ($$ == 0) return -1; } | TARGET ROLE { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_ROLE | CEXPR_TARGET), CEXPR_EQ); if ($$ == 0) return -1; } | ROLE role_mls_op { $$ = define_cexpr(CEXPR_ATTR, CEXPR_ROLE, $2); if ($$ == 0) return -1; } | SOURCE TYPE { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, CEXPR_TYPE, CEXPR_EQ); if ($$ == 0) return -1; } | TARGET TYPE { if (insert_separator(1)) return -1; } names_push { $$ = define_cexpr(CEXPR_NAMES, (CEXPR_TYPE | CEXPR_TARGET), CEXPR_EQ); if ($$ == 0) return -1; } | L1 role_mls_op L2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1L2, $2); if ($$ == 0) return -1; } | L1 role_mls_op H2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1H2, $2); if ($$ == 0) return -1; } | H1 role_mls_op L2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_H1L2, $2); if ($$ == 0) return -1; } | H1 role_mls_op H2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_H1H2, $2); if ($$ == 0) return -1; } | L1 role_mls_op H1 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L1H1, $2); if ($$ == 0) return -1; } | L2 role_mls_op H2 { $$ = define_cexpr(CEXPR_ATTR, CEXPR_L2H2, $2); if ($$ == 0) return -1; } ; op : EQUALS { $$ = CEXPR_EQ; } | NOTEQUAL { $$ = CEXPR_NEQ; } ; role_mls_op : op { $$ = $1; } | DOM { $$ = CEXPR_DOM; } | DOMBY { $$ = CEXPR_DOMBY; } | INCOMP { $$ = CEXPR_INCOMP; } ; users : user_def | users user_def ; user_def : USER identifier ROLES names opt_mls_user ';' {if (define_user()) return -1;} ; opt_mls_user : LEVEL mls_level_def RANGE mls_range_def | ; initial_sid_contexts : initial_sid_context_def | initial_sid_contexts initial_sid_context_def ; initial_sid_context_def : SID identifier security_context_def {if (define_initial_sid_context()) return -1;} ; opt_dev_contexts : dev_contexts | ; dev_contexts : dev_context_def | dev_contexts dev_context_def ; dev_context_def : pirq_context_def | iomem_context_def | ioport_context_def | pci_context_def ; pirq_context_def : PIRQCON number security_context_def {if (define_pirq_context($2)) return -1;} ; iomem_context_def : IOMEMCON number security_context_def {if (define_iomem_context($2,$2)) return -1;} | IOMEMCON number '-' number security_context_def {if (define_iomem_context($2,$4)) return -1;} ; ioport_context_def : IOPORTCON number security_context_def {if (define_ioport_context($2,$2)) return -1;} | IOPORTCON number '-' number security_context_def {if (define_ioport_context($2,$4)) return -1;} ; pci_context_def : PCIDEVICECON number security_context_def {if (define_pcidevice_context($2)) return -1;} ; opt_fs_contexts : fs_contexts | ; fs_contexts : fs_context_def | fs_contexts fs_context_def ; fs_context_def : FSCON number number security_context_def security_context_def {if (define_fs_context($2,$3)) return -1;} ; net_contexts : opt_port_contexts opt_netif_contexts opt_node_contexts ; opt_port_contexts : port_contexts | ; port_contexts : port_context_def | port_contexts port_context_def ; port_context_def : PORTCON identifier number security_context_def {if (define_port_context($3,$3)) return -1;} | PORTCON identifier number '-' number security_context_def {if (define_port_context($3,$5)) return -1;} ; opt_netif_contexts : netif_contexts | ; netif_contexts : netif_context_def | netif_contexts netif_context_def ; netif_context_def : NETIFCON identifier security_context_def security_context_def {if (define_netif_context()) return -1;} ; opt_node_contexts : node_contexts | ; node_contexts : node_context_def | node_contexts node_context_def ; node_context_def : NODECON ipv4_addr_def ipv4_addr_def security_context_def {if (define_ipv4_node_context()) return -1;} | NODECON ipv6_addr ipv6_addr security_context_def {if (define_ipv6_node_context()) return -1;} ; opt_fs_uses : fs_uses | ; fs_uses : fs_use_def | fs_uses fs_use_def ; fs_use_def : FSUSEXATTR filesystem security_context_def ';' {if (define_fs_use(SECURITY_FS_USE_XATTR)) return -1;} | FSUSETASK identifier security_context_def ';' {if (define_fs_use(SECURITY_FS_USE_TASK)) return -1;} | FSUSETRANS identifier security_context_def ';' {if (define_fs_use(SECURITY_FS_USE_TRANS)) return -1;} ; opt_genfs_contexts : genfs_contexts | ; genfs_contexts : genfs_context_def | genfs_contexts genfs_context_def ; genfs_context_def : GENFSCON filesystem path '-' identifier security_context_def {if (define_genfs_context(1)) return -1;} | GENFSCON filesystem path '-' '-' {insert_id("-", 0);} security_context_def {if (define_genfs_context(1)) return -1;} | GENFSCON filesystem path security_context_def {if (define_genfs_context(0)) return -1;} ; ipv4_addr_def : IPV4_ADDR { if (insert_id(yytext,0)) return -1; } ; security_context_def : identifier ':' identifier ':' identifier opt_mls_range_def ; opt_mls_range_def : ':' mls_range_def | ; mls_range_def : mls_level_def '-' mls_level_def {if (insert_separator(0)) return -1;} | mls_level_def {if (insert_separator(0)) return -1;} ; mls_level_def : identifier ':' id_comma_list {if (insert_separator(0)) return -1;} | identifier {if (insert_separator(0)) return -1;} ; id_comma_list : identifier | id_comma_list ',' identifier ; tilde : '~' ; asterisk : '*' ; names : identifier { if (insert_separator(0)) return -1; } | nested_id_set { if (insert_separator(0)) return -1; } | asterisk { if (insert_id("*", 0)) return -1; if (insert_separator(0)) return -1; } | tilde identifier { if (insert_id("~", 0)) return -1; if (insert_separator(0)) return -1; } | tilde nested_id_set { if (insert_id("~", 0)) return -1; if (insert_separator(0)) return -1; } | identifier '-' { if (insert_id("-", 0)) return -1; } identifier { if (insert_separator(0)) return -1; } ; tilde_push : tilde { if (insert_id("~", 1)) return -1; } ; asterisk_push : asterisk { if (insert_id("*", 1)) return -1; } ; names_push : identifier_push | '{' identifier_list_push '}' | asterisk_push | tilde_push identifier_push | tilde_push '{' identifier_list_push '}' ; identifier_list_push : identifier_push | identifier_list_push identifier_push ; identifier_push : IDENTIFIER { if (insert_id(yytext, 1)) return -1; } ; identifier_list : identifier | identifier_list identifier ; nested_id_set : '{' nested_id_list '}' ; nested_id_list : nested_id_element | nested_id_list nested_id_element ; nested_id_element : identifier | '-' { if (insert_id("-", 0)) return -1; } identifier | nested_id_set ; identifier : IDENTIFIER { if (insert_id(yytext,0)) return -1; } ; filesystem : FILESYSTEM { if (insert_id(yytext,0)) return -1; } | IDENTIFIER { if (insert_id(yytext,0)) return -1; } ; path : PATH { if (insert_id(yytext,0)) return -1; } ; filename : FILENAME { yytext[strlen(yytext) - 1] = '\0'; if (insert_id(yytext + 1,0)) return -1; } ; number : NUMBER { $$ = strtoul(yytext,NULL,0); } ; ipv6_addr : IPV6_ADDR { if (insert_id(yytext,0)) return -1; } ; policycap_def : POLICYCAP identifier ';' {if (define_polcap()) return -1;} ; permissive_def : PERMISSIVE identifier ';' {if (define_permissive()) return -1;} /*********** module grammar below ***********/ module_policy : module_def avrules_block { if (end_avrule_block(pass) == -1) return -1; if (policydb_index_others(NULL, policydbp, 0)) return -1; } ; module_def : MODULE identifier version_identifier ';' { if (define_policy(pass, 1) == -1) return -1; } ; version_identifier : VERSION_IDENTIFIER { if (insert_id(yytext,0)) return -1; } | number { if (insert_id(yytext,0)) return -1; } | ipv4_addr_def /* version can look like ipv4 address */ ; avrules_block : avrule_decls avrule_user_defs ; avrule_decls : avrule_decls avrule_decl | avrule_decl ; avrule_decl : rbac_decl | te_decl | cond_stmt_def | require_block | optional_block | ';' ; require_block : REQUIRE '{' require_list '}' ; require_list : require_list require_decl | require_decl ; require_decl : require_class ';' | require_decl_def require_id_list ';' ; require_class : CLASS identifier names { if (require_class(pass)) return -1; } ; require_decl_def : ROLE { $$ = require_role; } | TYPE { $$ = require_type; } | ATTRIBUTE { $$ = require_attribute; } | ATTRIBUTE_ROLE { $$ = require_attribute_role; } | USER { $$ = require_user; } | BOOL { $$ = require_bool; } | TUNABLE { $$ = require_tunable; } | SENSITIVITY { $$ = require_sens; } | CATEGORY { $$ = require_cat; } ; require_id_list : identifier { if ($0 (pass)) return -1; } | require_id_list ',' identifier { if ($0 (pass)) return -1; } ; optional_block : optional_decl '{' avrules_block '}' { if (end_avrule_block(pass) == -1) return -1; } optional_else { if (end_optional(pass) == -1) return -1; } ; optional_else : else_decl '{' avrules_block '}' { if (end_avrule_block(pass) == -1) return -1; } | /* empty */ ; optional_decl : OPTIONAL { if (begin_optional(pass) == -1) return -1; } ; else_decl : ELSE { if (begin_optional_else(pass) == -1) return -1; } ; avrule_user_defs : user_def avrule_user_defs | /* empty */ ; checkpolicy-2.2/policy_scan.l000066400000000000000000000161601223423440700163370ustar00rootroot00000000000000 /* * Author : Stephen Smalley, */ /* Updated: David Caplan, * * Added conditional policy language extensions * * Jason Tang * * Added support for binary policy modules * * Copyright (C) 2003-5 Tresys Technology, LLC * 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. */ /* FLASK */ %{ #include #include #include #include typedef int (* require_func_t)(); #ifdef ANDROID #include "policy_parse.h" #else #include "y.tab.h" #endif static char linebuf[2][255]; static unsigned int lno = 0; int yywarn(char *msg); void set_source_file(const char *name); char source_file[PATH_MAX]; unsigned long source_lineno = 1; unsigned long policydb_lineno = 1; unsigned int policydb_errors = 0; %} %option noinput nounput noyywrap %array letter [A-Za-z] digit [0-9] alnum [a-zA-Z0-9] hexval [0-9A-Fa-f] %% \n.* { strncpy(linebuf[lno], yytext+1, 255); linebuf[lno][254] = 0; lno = 1 - lno; policydb_lineno++; source_lineno++; yyless(1); } CLONE | clone { return(CLONE); } COMMON | common { return(COMMON); } CLASS | class { return(CLASS); } CONSTRAIN | constrain { return(CONSTRAIN); } VALIDATETRANS | validatetrans { return(VALIDATETRANS); } INHERITS | inherits { return(INHERITS); } SID | sid { return(SID); } ROLE | role { return(ROLE); } ROLES | roles { return(ROLES); } ROLEATTRIBUTE | roleattribute { return(ROLEATTRIBUTE);} ATTRIBUTE_ROLE | attribute_role { return(ATTRIBUTE_ROLE);} TYPES | types { return(TYPES); } TYPEALIAS | typealias { return(TYPEALIAS); } TYPEATTRIBUTE | typeattribute { return(TYPEATTRIBUTE); } TYPEBOUNDS | typebounds { return(TYPEBOUNDS); } TYPE | type { return(TYPE); } BOOL | bool { return(BOOL); } TUNABLE | tunable { return(TUNABLE); } IF | if { return(IF); } ELSE | else { return(ELSE); } ALIAS | alias { return(ALIAS); } ATTRIBUTE | attribute { return(ATTRIBUTE); } TYPE_TRANSITION | type_transition { return(TYPE_TRANSITION); } TYPE_MEMBER | type_member { return(TYPE_MEMBER); } TYPE_CHANGE | type_change { return(TYPE_CHANGE); } ROLE_TRANSITION | role_transition { return(ROLE_TRANSITION); } RANGE_TRANSITION | range_transition { return(RANGE_TRANSITION); } SENSITIVITY | sensitivity { return(SENSITIVITY); } DOMINANCE | dominance { return(DOMINANCE); } CATEGORY | category { return(CATEGORY); } LEVEL | level { return(LEVEL); } RANGE | range { return(RANGE); } MLSCONSTRAIN | mlsconstrain { return(MLSCONSTRAIN); } MLSVALIDATETRANS | mlsvalidatetrans { return(MLSVALIDATETRANS); } USER | user { return(USER); } NEVERALLOW | neverallow { return(NEVERALLOW); } ALLOW | allow { return(ALLOW); } AUDITALLOW | auditallow { return(AUDITALLOW); } AUDITDENY | auditdeny { return(AUDITDENY); } DONTAUDIT | dontaudit { return(DONTAUDIT); } SOURCE | source { return(SOURCE); } TARGET | target { return(TARGET); } SAMEUSER | sameuser { return(SAMEUSER);} module|MODULE { return(MODULE); } require|REQUIRE { return(REQUIRE); } optional|OPTIONAL { return(OPTIONAL); } OR | or { return(OR);} AND | and { return(AND);} NOT | not { return(NOT);} xor | XOR { return(XOR); } eq | EQ { return(EQUALS);} true | TRUE { return(CTRUE); } false | FALSE { return(CFALSE); } dom | DOM { return(DOM);} domby | DOMBY { return(DOMBY);} INCOMP | incomp { return(INCOMP);} fscon | FSCON { return(FSCON);} portcon | PORTCON { return(PORTCON);} netifcon | NETIFCON { return(NETIFCON);} nodecon | NODECON { return(NODECON);} pirqcon | PIRQCON { return(PIRQCON);} iomemcon | IOMEMCON { return(IOMEMCON);} ioportcon | IOPORTCON { return(IOPORTCON);} pcidevicecon | PCIDEVICECON { return(PCIDEVICECON);} fs_use_xattr | FS_USE_XATTR { return(FSUSEXATTR);} fs_use_task | FS_USE_TASK { return(FSUSETASK);} fs_use_trans | FS_USE_TRANS { return(FSUSETRANS);} genfscon | GENFSCON { return(GENFSCON);} r1 | R1 { return(R1); } r2 | R2 { return(R2); } r3 | R3 { return(R3); } u1 | U1 { return(U1); } u2 | U2 { return(U2); } u3 | U3 { return(U3); } t1 | T1 { return(T1); } t2 | T2 { return(T2); } t3 | T3 { return(T3); } l1 | L1 { return(L1); } l2 | L2 { return(L2); } h1 | H1 { return(H1); } h2 | H2 { return(H2); } policycap | POLICYCAP { return(POLICYCAP); } permissive | PERMISSIVE { return(PERMISSIVE); } default_user | DEFAULT_USER { return(DEFAULT_USER); } default_role | DEFAULT_ROLE { return(DEFAULT_ROLE); } default_type | DEFAULT_TYPE { return(DEFAULT_TYPE); } default_range | DEFAULT_RANGE { return(DEFAULT_RANGE); } low-high | LOW-HIGH { return(LOW_HIGH); } high | HIGH { return(HIGH); } low | LOW { return(LOW); } "/"({alnum}|[_\.\-/])* { return(PATH); } \"({alnum}|[_\.\-\+\~\: ])+\" { return(FILENAME); } {letter}({alnum}|[_\-])*([\.]?({alnum}|[_\-]))* { return(IDENTIFIER); } {alnum}*{letter}{alnum}* { return(FILESYSTEM); } {digit}+|0x{hexval}+ { return(NUMBER); } {digit}{1,3}(\.{digit}{1,3}){3} { return(IPV4_ADDR); } {hexval}{0,4}":"{hexval}{0,4}":"({hexval}|[:.])* { return(IPV6_ADDR); } {digit}+(\.({alnum}|[_.])*)? { return(VERSION_IDENTIFIER); } #line[ ]1[ ]\"[^\n]*\" { set_source_file(yytext+9); } #line[ ]{digit}+ { source_lineno = atoi(yytext+6)-1; } #[^\n]* { /* delete comments */ } [ \t\f]+ { /* delete whitespace */ } "==" { return(EQUALS); } "!=" { return (NOTEQUAL); } "&&" { return (AND); } "||" { return (OR); } "!" { return (NOT); } "^" { return (XOR); } "," | ":" | ";" | "(" | ")" | "{" | "}" | "[" | "-" | "." | "]" | "~" | "*" { return(yytext[0]); } . { yywarn("unrecognized character");} %% int yyerror(char *msg) { if (source_file[0]) fprintf(stderr, "%s:%ld:", source_file, source_lineno); else fprintf(stderr, "(unknown source)::"); fprintf(stderr, "ERROR '%s' at token '%s' on line %ld:\n%s\n%s\n", msg, yytext, policydb_lineno, linebuf[0], linebuf[1]); policydb_errors++; return -1; } int yywarn(char *msg) { if (source_file[0]) fprintf(stderr, "%s:%ld:", source_file, source_lineno); else fprintf(stderr, "(unknown source)::"); fprintf(stderr, "WARNING '%s' at token '%s' on line %ld:\n%s\n%s\n", msg, yytext, policydb_lineno, linebuf[0], linebuf[1]); return 0; } void set_source_file(const char *name) { source_lineno = 1; strncpy(source_file, name, sizeof(source_file)-1); source_file[sizeof(source_file)-1] = '\0'; } checkpolicy-2.2/queue.c000066400000000000000000000047541223423440700151550ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * Implementation of the double-ended queue type. */ #include #include "queue.h" queue_t queue_create(void) { queue_t q; q = (queue_t) malloc(sizeof(struct queue_info)); if (q == NULL) return NULL; q->head = q->tail = NULL; return q; } int queue_insert(queue_t q, queue_element_t e) { queue_node_ptr_t newnode; if (!q) return -1; newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node)); if (newnode == NULL) return -1; newnode->element = e; newnode->next = NULL; if (q->head == NULL) { q->head = q->tail = newnode; } else { q->tail->next = newnode; q->tail = newnode; } return 0; } int queue_push(queue_t q, queue_element_t e) { queue_node_ptr_t newnode; if (!q) return -1; newnode = (queue_node_ptr_t) malloc(sizeof(struct queue_node)); if (newnode == NULL) return -1; newnode->element = e; newnode->next = NULL; if (q->head == NULL) { q->head = q->tail = newnode; } else { newnode->next = q->head; q->head = newnode; } return 0; } queue_element_t queue_remove(queue_t q) { queue_node_ptr_t node; queue_element_t e; if (!q) return NULL; if (q->head == NULL) return NULL; node = q->head; q->head = q->head->next; if (q->head == NULL) q->tail = NULL; e = node->element; free(node); return e; } queue_element_t queue_head(queue_t q) { if (!q) return NULL; if (q->head == NULL) return NULL; return q->head->element; } void queue_destroy(queue_t q) { queue_node_ptr_t p, temp; if (!q) return; p = q->head; while (p != NULL) { temp = p; p = p->next; free(temp); } free(q); } int queue_map(queue_t q, int (*f) (queue_element_t, void *), void *vp) { queue_node_ptr_t p; int ret; if (!q) return 0; p = q->head; while (p != NULL) { ret = f(p->element, vp); if (ret) return ret; p = p->next; } return 0; } void queue_map_remove_on_error(queue_t q, int (*f) (queue_element_t, void *), void (*g) (queue_element_t, void *), void *vp) { queue_node_ptr_t p, last, temp; int ret; if (!q) return; last = NULL; p = q->head; while (p != NULL) { ret = f(p->element, vp); if (ret) { if (last) { last->next = p->next; if (last->next == NULL) q->tail = last; } else { q->head = p->next; if (q->head == NULL) q->tail = NULL; } temp = p; p = p->next; g(temp->element, vp); free(temp); } else { last = p; p = p->next; } } return; } /* FLASK */ checkpolicy-2.2/queue.h000066400000000000000000000027621223423440700151570ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * A double-ended queue is a singly linked list of * elements of arbitrary type that may be accessed * at either end. */ #ifndef _QUEUE_H_ #define _QUEUE_H_ typedef void *queue_element_t; typedef struct queue_node *queue_node_ptr_t; typedef struct queue_node { queue_element_t element; queue_node_ptr_t next; } queue_node_t; typedef struct queue_info { queue_node_ptr_t head; queue_node_ptr_t tail; } queue_info_t; typedef queue_info_t *queue_t; queue_t queue_create(void); int queue_insert(queue_t, queue_element_t); int queue_push(queue_t, queue_element_t); queue_element_t queue_remove(queue_t); queue_element_t queue_head(queue_t); void queue_destroy(queue_t); /* Applies the specified function f to each element in the specified queue. In addition to passing the element to f, queue_map passes the specified void* pointer to f on each invocation. If f returns a non-zero status, then queue_map will cease iterating through the hash table and will propagate the error return to its caller. */ int queue_map(queue_t, int (*f) (queue_element_t, void *), void *); /* Same as queue_map, except that if f returns a non-zero status, then the element will be removed from the queue and the g function will be applied to the element. */ void queue_map_remove_on_error(queue_t, int (*f) (queue_element_t, void *), void (*g) (queue_element_t, void *), void *); #endif /* FLASK */ checkpolicy-2.2/test/000077500000000000000000000000001223423440700146325ustar00rootroot00000000000000checkpolicy-2.2/test/.gitignore000066400000000000000000000000161223423440700166170ustar00rootroot00000000000000dismod dispol checkpolicy-2.2/test/Makefile000066400000000000000000000005641223423440700162770ustar00rootroot00000000000000# # Makefile for building the dispol program # PREFIX ?= $(DESTDIR)/usr BINDIR=$(PREFIX)/bin LIBDIR ?= $(PREFIX)/lib INCLUDEDIR ?= $(PREFIX)/include CFLAGS ?= -g -Wall -W -Werror -O2 -pipe override CFLAGS += -I$(INCLUDEDIR) LDLIBS=-lfl -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR) all: dispol dismod dispol: dispol.o dismod: dismod.o clean: -rm -f dispol dismod *.o checkpolicy-2.2/test/dismod.c000066400000000000000000000565031223423440700162660ustar00rootroot00000000000000 /* Authors: Frank Mayer and Karl MacMillan * * Copyright (C) 2003,2004,2005 Tresys Technology, LLC * 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. */ /* * dismod.c * * Test program to the contents of a binary policy in text * form. * * dismod binary_mod_file */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __BYTE_ORDER == __LITTLE_ENDIAN #define le32_to_cpu(x) (x) #else #define le32_to_cpu(x) bswap_32(x) #endif #define DISPLAY_AVBLOCK_COND_AVTAB 0 #define DISPLAY_AVBLOCK_UNCOND_AVTAB 1 #define DISPLAY_AVBLOCK_ROLE_TYPE_NODE 2 /* unused? */ #define DISPLAY_AVBLOCK_ROLE_TRANS 3 #define DISPLAY_AVBLOCK_ROLE_ALLOW 4 #define DISPLAY_AVBLOCK_REQUIRES 5 #define DISPLAY_AVBLOCK_DECLARES 6 #define DISPLAY_AVBLOCK_FILENAME_TRANS 7 static policydb_t policydb; extern unsigned int ss_initialized; int policyvers = MOD_POLICYDB_VERSION_BASE; static const char *symbol_labels[9] = { "commons", "classes", "roles ", "types ", "users ", "bools ", "levels ", "cats ", "attribs" }; void usage(char *progname) { printf("usage: %s binary_pol_file\n\n", progname); exit(1); } static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p, FILE * fp) { char *perm; fprintf(fp, "{"); perm = sepol_av_to_string(p, class, mask); if (perm) fprintf(fp, "%s ", perm); fprintf(fp, "}"); } static void render_access_bitmap(ebitmap_t * map, uint32_t class, policydb_t * p, FILE * fp) { unsigned int i; char *perm; fprintf(fp, "{"); for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) { if (ebitmap_get_bit(map, i)) { perm = sepol_av_to_string(p, class, 1 << i); if (perm) fprintf(fp, " %s", perm); } } fprintf(fp, " }"); } static void display_id(policydb_t * p, FILE * fp, uint32_t symbol_type, uint32_t symbol_value, char *prefix) { char *id = p->sym_val_to_name[symbol_type][symbol_value]; scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symbol_type].table, id); assert(scope != NULL); if (scope->scope == SCOPE_REQ) { fprintf(fp, " [%s%s]", prefix, id); } else { fprintf(fp, " %s%s", prefix, id); } } int display_type_set(type_set_t * set, uint32_t flags, policydb_t * policy, FILE * fp) { unsigned int i, num_types; if (set->flags & TYPE_STAR) { fprintf(fp, " * "); return 0; } else if (set->flags & TYPE_COMP) { fprintf(fp, " ~"); } num_types = 0; if (flags & RULE_SELF) { num_types++; } for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); i++) { if (!ebitmap_get_bit(&set->types, i)) continue; num_types++; if (num_types > 1) break; } if (num_types <= 1) { for (i = ebitmap_startbit(&set->negset); i < ebitmap_length(&set->negset); i++) { if (!ebitmap_get_bit(&set->negset, i)) continue; num_types++; if (num_types > 1) break; } } if (num_types > 1) fprintf(fp, "{"); for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); i++) { if (!ebitmap_get_bit(&set->types, i)) continue; display_id(policy, fp, SYM_TYPES, i, ""); } for (i = ebitmap_startbit(&set->negset); i < ebitmap_length(&set->negset); i++) { if (!ebitmap_get_bit(&set->negset, i)) continue; display_id(policy, fp, SYM_TYPES, i, "-"); } if (flags & RULE_SELF) { fprintf(fp, " self"); } if (num_types > 1) fprintf(fp, " }"); return 0; } int display_mod_role_set(role_set_t * roles, policydb_t * p, FILE * fp) { unsigned int i, num = 0; if (roles->flags & ROLE_STAR) { fprintf(fp, " * "); return 0; } else if (roles->flags & ROLE_COMP) { fprintf(fp, " ~"); } for (i = ebitmap_startbit(&roles->roles); i < ebitmap_length(&roles->roles); i++) { if (!ebitmap_get_bit(&roles->roles, i)) continue; num++; if (num > 1) { fprintf(fp, "{"); break; } } for (i = ebitmap_startbit(&roles->roles); i < ebitmap_length(&roles->roles); i++) { if (ebitmap_get_bit(&roles->roles, i)) display_id(p, fp, SYM_ROLES, i, ""); } if (num > 1) fprintf(fp, " }"); return 0; } int display_avrule(avrule_t * avrule, policydb_t * policy, FILE * fp) { class_perm_node_t *cur; int num_classes; if (avrule == NULL) { fprintf(fp, " \n"); return 0; } if (avrule->specified & AVRULE_AV) { if (avrule->specified & AVRULE_ALLOWED) { fprintf(fp, " allow"); } if (avrule->specified & AVRULE_AUDITALLOW) { fprintf(fp, " auditallow "); } if (avrule->specified & AVRULE_DONTAUDIT) { fprintf(fp, " dontaudit"); } } else if (avrule->specified & AVRULE_TYPE) { if (avrule->specified & AVRULE_TRANSITION) { fprintf(fp, " type_transition"); } if (avrule->specified & AVRULE_MEMBER) { fprintf(fp, " type_member"); } if (avrule->specified & AVRULE_CHANGE) { fprintf(fp, " type_change"); } } else if (avrule->specified & AVRULE_NEVERALLOW) { fprintf(fp, " neverallow"); } else { fprintf(fp, " ERROR: no valid rule type specified\n"); return -1; } if (display_type_set(&avrule->stypes, 0, policy, fp)) return -1; if (display_type_set(&avrule->ttypes, avrule->flags, policy, fp)) return -1; fprintf(fp, " :"); cur = avrule->perms; num_classes = 0; while (cur) { num_classes++; if (num_classes > 1) break; cur = cur->next; } if (num_classes > 1) fprintf(fp, " {"); cur = avrule->perms; while (cur) { display_id(policy, fp, SYM_CLASSES, cur->class - 1, ""); cur = cur->next; } if (num_classes > 1) fprintf(fp, " }"); fprintf(fp, " "); if (avrule->specified & (AVRULE_AV | AVRULE_NEVERALLOW)) { render_access_mask(avrule->perms->data, avrule->perms->class, policy, fp); } else if (avrule->specified & AVRULE_TYPE) { display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, ""); } fprintf(fp, ";\n"); return 0; } int display_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { type_datum_t *type; FILE *fp; unsigned int i, first_attrib = 1; type = (type_datum_t *) datum; fp = (FILE *) data; if (type->primary) { display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); fprintf(fp, " [%d]: ", type->s.value); } else { /* as that aliases have no value of their own and that * they can never be required by a module, use this * alternative way of displaying a name */ fprintf(fp, " %s [%d]: ", (char *)key, type->s.value); } if (type->flavor == TYPE_ATTRIB) { fprintf(fp, "attribute for types"); for (i = ebitmap_startbit(&type->types); i < ebitmap_length(&type->types); i++) { if (!ebitmap_get_bit(&type->types, i)) continue; if (first_attrib) { first_attrib = 0; } else { fprintf(fp, ","); } display_id(&policydb, fp, SYM_TYPES, i, ""); } } else if (type->primary) { fprintf(fp, "type"); } else { fprintf(fp, "alias for type"); display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); } fprintf(fp, " flags:%x\n", type->flags); return 0; } int display_types(policydb_t * p, FILE * fp) { if (hashtab_map(p->p_types.table, display_type_callback, fp)) return -1; return 0; } int display_users(policydb_t * p, FILE * fp) { unsigned int i, j; ebitmap_t *bitmap; for (i = 0; i < p->p_users.nprim; i++) { display_id(p, fp, SYM_USERS, i, ""); fprintf(fp, ":"); bitmap = &(p->user_val_to_struct[i]->roles.roles); for (j = ebitmap_startbit(bitmap); j < ebitmap_length(bitmap); j++) { if (ebitmap_get_bit(bitmap, j)) { display_id(p, fp, SYM_ROLES, j, ""); } } fprintf(fp, "\n"); } return 0; } int display_bools(policydb_t * p, FILE * fp) { unsigned int i; for (i = 0; i < p->p_bools.nprim; i++) { display_id(p, fp, SYM_BOOLS, i, ""); fprintf(fp, " : %d\n", p->bool_val_to_struct[i]->state); } return 0; } void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp) { cond_expr_t *cur; for (cur = exp; cur != NULL; cur = cur->next) { switch (cur->expr_type) { case COND_BOOL: fprintf(fp, "%s ", p->p_bool_val_to_name[cur->bool - 1]); break; case COND_NOT: fprintf(fp, "! "); break; case COND_OR: fprintf(fp, "|| "); break; case COND_AND: fprintf(fp, "&& "); break; case COND_XOR: fprintf(fp, "^ "); break; case COND_EQ: fprintf(fp, "== "); break; case COND_NEQ: fprintf(fp, "!= "); break; default: fprintf(fp, "error!"); break; } } } void display_policycon(FILE * fp) { /* There was an attempt to implement this at one time. Look through * git history to find it. */ fprintf(fp, "Sorry, not implemented\n"); } void display_initial_sids(policydb_t * p, FILE * fp) { ocontext_t *cur; char *user, *role, *type; fprintf(fp, "Initial SIDs:\n"); for (cur = p->ocontexts[OCON_ISID]; cur != NULL; cur = cur->next) { user = p->p_user_val_to_name[cur->context[0].user - 1]; role = p->p_role_val_to_name[cur->context[0].role - 1]; type = p->p_type_val_to_name[cur->context[0].type - 1]; fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", cur->u.name, cur->sid[0], user, role, type); } #if 0 fprintf(fp, "Policy Initial SIDs:\n"); for (cur = p->ocontexts[OCON_POLICYISID]; cur != NULL; cur = cur->next) { user = p->p_user_val_to_name[cur->context[0].user - 1]; role = p->p_role_val_to_name[cur->context[0].role - 1]; type = p->p_type_val_to_name[cur->context[0].type - 1]; fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", cur->u.name, cur->sid[0], user, role, type); } #endif } void display_class_set(ebitmap_t *classes, policydb_t *p, FILE *fp) { unsigned int i, num = 0; for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { if (!ebitmap_get_bit(classes, i)) continue; num++; if (num > 1) { fprintf(fp, "{"); break; } } for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { if (ebitmap_get_bit(classes, i)) display_id(p, fp, SYM_CLASSES, i, ""); } if (num > 1) fprintf(fp, " }"); } void display_role_trans(role_trans_rule_t * tr, policydb_t * p, FILE * fp) { for (; tr; tr = tr->next) { fprintf(fp, "role transition "); display_mod_role_set(&tr->roles, p, fp); display_type_set(&tr->types, 0, p, fp); fprintf(fp, " :"); display_class_set(&tr->classes, p, fp); display_id(p, fp, SYM_ROLES, tr->new_role - 1, ""); fprintf(fp, "\n"); } } void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp) { for (; ra; ra = ra->next) { fprintf(fp, "role allow "); display_mod_role_set(&ra->roles, p, fp); display_mod_role_set(&ra->new_roles, p, fp); fprintf(fp, "\n"); } } static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp) { fprintf(fp, "filename transition"); for (; tr; tr = tr->next) { display_type_set(&tr->stypes, 0, p, fp); display_type_set(&tr->ttypes, 0, p, fp); display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":"); display_id(p, fp, SYM_TYPES, tr->otype - 1, ""); fprintf(fp, " %s\n", tr->name); } } int role_display_callback(hashtab_key_t key __attribute__((unused)), hashtab_datum_t datum, void *data) { role_datum_t *role; FILE *fp; role = (role_datum_t *) datum; fp = (FILE *) data; fprintf(fp, "role:"); display_id(&policydb, fp, SYM_ROLES, role->s.value - 1, ""); fprintf(fp, " types: "); display_type_set(&role->types, 0, &policydb, fp); fprintf(fp, "\n"); return 0; } static int display_scope_index(scope_index_t * indices, policydb_t * p, FILE * out_fp) { unsigned int i; for (i = 0; i < SYM_NUM; i++) { unsigned int any_found = 0, j; fprintf(out_fp, "%s:", symbol_labels[i]); for (j = ebitmap_startbit(&indices->scope[i]); j < ebitmap_length(&indices->scope[i]); j++) { if (ebitmap_get_bit(&indices->scope[i], j)) { any_found = 1; fprintf(out_fp, " %s", p->sym_val_to_name[i][j]); if (i == SYM_CLASSES) { if (j < indices->class_perms_len) { render_access_bitmap(indices-> class_perms_map + j, j + 1, p, out_fp); } else { fprintf(out_fp, ""); } } } } if (!any_found) { fprintf(out_fp, " "); } fprintf(out_fp, "\n"); } return 0; } #if 0 int display_cond_expressions(policydb_t * p, FILE * fp) { cond_node_t *cur; cond_av_list_t *av_cur; for (cur = p->cond_list; cur != NULL; cur = cur->next) { fprintf(fp, "expression: "); display_expr(p, cur->expr, fp); fprintf(fp, "current state: %d\n", cur->cur_state); fprintf(fp, "True list:\n"); for (av_cur = cur->true_list; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } fprintf(fp, "False list:\n"); for (av_cur = cur->false_list; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } } return 0; } int change_bool(char *name, int state, policydb_t * p, FILE * fp) { cond_bool_datum_t *bool; bool = hashtab_search(p->p_bools.table, name); if (bool == NULL) { fprintf(fp, "Could not find bool %s\n", name); return -1; } bool->state = state; evaluate_conds(p); return 0; } #endif int display_avdecl(avrule_decl_t * decl, int field, policydb_t * policy, FILE * out_fp) { fprintf(out_fp, "decl %u:%s\n", decl->decl_id, (decl->enabled ? " [enabled]" : "")); switch (field) { case DISPLAY_AVBLOCK_COND_AVTAB:{ cond_list_t *cond = decl->cond_list; avrule_t *avrule; while (cond) { fprintf(out_fp, "expression: "); display_expr(&policydb, cond->expr, out_fp); fprintf(out_fp, "current state: %d\n", cond->cur_state); fprintf(out_fp, "True list:\n"); avrule = cond->avtrue_list; while (avrule) { display_avrule(avrule, &policydb, out_fp); avrule = avrule->next; } fprintf(out_fp, "False list:\n"); avrule = cond->avfalse_list; while (avrule) { display_avrule(avrule, &policydb, out_fp); avrule = avrule->next; } cond = cond->next; } break; } case DISPLAY_AVBLOCK_UNCOND_AVTAB:{ avrule_t *avrule = decl->avrules; if (avrule == NULL) { fprintf(out_fp, " \n"); } while (avrule != NULL) { if (display_avrule(avrule, policy, out_fp)) return -1; avrule = avrule->next; } break; } case DISPLAY_AVBLOCK_ROLE_TYPE_NODE:{ /* role_type_node */ break; } case DISPLAY_AVBLOCK_ROLE_TRANS:{ display_role_trans(decl->role_tr_rules, policy, out_fp); break; } case DISPLAY_AVBLOCK_ROLE_ALLOW:{ display_role_allow(decl->role_allow_rules, policy, out_fp); break; } case DISPLAY_AVBLOCK_REQUIRES:{ if (display_scope_index (&decl->required, policy, out_fp)) { return -1; } break; } case DISPLAY_AVBLOCK_DECLARES:{ if (display_scope_index (&decl->declared, policy, out_fp)) { return -1; } break; } case DISPLAY_AVBLOCK_FILENAME_TRANS: display_filename_trans(decl->filename_trans_rules, policy, out_fp); break; default:{ assert(0); } } return 0; /* should never get here */ } int display_avblock(int field, policydb_t * policy, FILE * out_fp) { avrule_block_t *block = policydb.global; while (block != NULL) { fprintf(out_fp, "--- begin avrule block ---\n"); avrule_decl_t *decl = block->branch_list; while (decl != NULL) { if (display_avdecl(decl, field, policy, out_fp)) { return -1; } decl = decl->next; } block = block->next; } return 0; } int display_handle_unknown(policydb_t * p, FILE * out_fp) { if (p->handle_unknown == ALLOW_UNKNOWN) fprintf(out_fp, "Allow unknown classes and perms\n"); else if (p->handle_unknown == DENY_UNKNOWN) fprintf(out_fp, "Deny unknown classes and perms\n"); else if (p->handle_unknown == REJECT_UNKNOWN) fprintf(out_fp, "Reject unknown classes and perms\n"); return 0; } static int read_policy(char *filename, policydb_t * policy) { FILE *in_fp; struct policy_file f; int retval; uint32_t buf[1]; if ((in_fp = fopen(filename, "rb")) == NULL) { fprintf(stderr, "Can't open '%s': %s\n", filename, strerror(errno)); exit(1); } policy_file_init(&f); f.type = PF_USE_STDIO; f.fp = in_fp; /* peek at the first byte. if they are indicative of a package use the package reader, otherwise use the normal policy reader */ if (fread(buf, sizeof(uint32_t), 1, in_fp) != 1) { fprintf(stderr, "Could not read from policy.\n"); exit(1); } rewind(in_fp); if (le32_to_cpu(buf[0]) == SEPOL_MODULE_PACKAGE_MAGIC) { sepol_module_package_t *package; if (sepol_module_package_create(&package)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); exit(1); } package->policy = (sepol_policydb_t *) policy; package->file_contexts = NULL; retval = sepol_module_package_read(package, (sepol_policy_file_t *) & f, 1); free(package->file_contexts); } else { if (policydb_init(policy)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); exit(1); } retval = policydb_read(policy, &f, 1); } fclose(in_fp); return retval; } static void link_module(policydb_t * base, FILE * out_fp) { char module_name[80] = { 0 }; int ret; policydb_t module, *mods = &module; if (base->policy_type != POLICY_BASE) { printf("Can only link if initial file was a base policy.\n"); return; } printf("\nModule filename: "); fgets(module_name, sizeof(module_name), stdin); module_name[strlen(module_name) - 1] = '\0'; /* remove LF */ if (module_name[0] == '\0') { return; } /* read the binary policy */ fprintf(out_fp, "Reading module...\n"); if (read_policy(module_name, mods)) { fprintf(stderr, "%s: error(s) encountered while loading policy\n", module_name); exit(1); } if (module.policy_type != POLICY_MOD) { fprintf(stderr, "This file is not a loadable policy module.\n"); exit(1); } if (policydb_index_classes(&module) || policydb_index_others(NULL, &module, 0)) { fprintf(stderr, "Could not index module.\n"); exit(1); } ret = link_modules(NULL, base, &mods, 1, 0); if (ret != 0) { printf("Link failed (error %d)\n", ret); printf("(You will probably need to restart dismod.)\n"); } policydb_destroy(&module); return; } static void display_policycaps(policydb_t * p, FILE * fp) { ebitmap_node_t *node; const char *capname; char buf[64]; unsigned int i; fprintf(fp, "policy capabilities:\n"); ebitmap_for_each_bit(&p->policycaps, node, i) { if (ebitmap_node_get_bit(node, i)) { capname = sepol_polcap_getname(i); if (capname == NULL) { snprintf(buf, sizeof(buf), "unknown (%d)", i); capname = buf; } fprintf(fp, "\t%s\n", capname); } } } int menu() { printf("\nSelect a command:\n"); printf("1) display unconditional AVTAB\n"); printf("2) display conditional AVTAB\n"); printf("3) display users\n"); printf("4) display bools\n"); printf("5) display roles\n"); printf("6) display types, attributes, and aliases\n"); printf("7) display role transitions\n"); printf("8) display role allows\n"); printf("9) Display policycon\n"); printf("0) Display initial SIDs\n"); printf("\n"); printf("a) Display avrule requirements\n"); printf("b) Display avrule declarations\n"); printf("c) Display policy capabilities\n"); printf("l) Link in a module\n"); printf("u) Display the unknown handling setting\n"); printf("F) Display filename_trans rules\n"); printf("\n"); printf("f) set output file\n"); printf("m) display menu\n"); printf("q) quit\n"); return 0; } int main(int argc, char **argv) { FILE *out_fp = stdout; char ans[81], OutfileName[121]; if (argc != 2) usage(argv[0]); /* read the binary policy */ fprintf(out_fp, "Reading policy...\n"); if (policydb_init(&policydb)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); exit(1); } if (read_policy(argv[1], &policydb)) { fprintf(stderr, "%s: error(s) encountered while loading policy\n", argv[0]); exit(1); } if (policydb.policy_type != POLICY_BASE && policydb.policy_type != POLICY_MOD) { fprintf(stderr, "This file is neither a base nor loadable policy module.\n"); exit(1); } if (policydb_index_classes(&policydb)) { fprintf(stderr, "Error indexing classes\n"); exit(1); } if (policydb_index_others(NULL, &policydb, 1)) { fprintf(stderr, "Error indexing others\n"); exit(1); } if (policydb.policy_type == POLICY_BASE) { printf("Binary base policy file loaded.\n\n"); } else { printf("Binary policy module file loaded.\n"); printf("Module name: %s\n", policydb.name); printf("Module version: %s\n", policydb.version); printf("\n"); } menu(); for (;;) { printf("\nCommand (\'m\' for menu): "); fgets(ans, sizeof(ans), stdin); switch (ans[0]) { case '1': fprintf(out_fp, "unconditional avtab:\n"); display_avblock(DISPLAY_AVBLOCK_UNCOND_AVTAB, &policydb, out_fp); break; case '2': fprintf(out_fp, "conditional avtab:\n"); display_avblock(DISPLAY_AVBLOCK_COND_AVTAB, &policydb, out_fp); break; case '3': display_users(&policydb, out_fp); break; case '4': display_bools(&policydb, out_fp); break; case '5': if (hashtab_map (policydb.p_roles.table, role_display_callback, out_fp)) exit(1); break; case '6': if (display_types(&policydb, out_fp)) { fprintf(stderr, "Error displaying types\n"); exit(1); } break; case '7': fprintf(out_fp, "role transitions:\n"); display_avblock(DISPLAY_AVBLOCK_ROLE_TRANS, &policydb, out_fp); break; case '8': fprintf(out_fp, "role allows:\n"); display_avblock(DISPLAY_AVBLOCK_ROLE_ALLOW, &policydb, out_fp); break; case '9': display_policycon(out_fp); break; case '0': display_initial_sids(&policydb, out_fp); break; case 'a': fprintf(out_fp, "avrule block requirements:\n"); display_avblock(DISPLAY_AVBLOCK_REQUIRES, &policydb, out_fp); break; case 'b': fprintf(out_fp, "avrule block declarations:\n"); display_avblock(DISPLAY_AVBLOCK_DECLARES, &policydb, out_fp); break; case 'c': display_policycaps(&policydb, out_fp); break; case 'u': case 'U': display_handle_unknown(&policydb, out_fp); break; case 'f': printf ("\nFilename for output ( for screen output): "); fgets(OutfileName, sizeof(OutfileName), stdin); OutfileName[strlen(OutfileName) - 1] = '\0'; /* fix_string (remove LF) */ if (strlen(OutfileName) == 0) out_fp = stdout; else if ((out_fp = fopen(OutfileName, "w")) == NULL) { fprintf(stderr, "Cannot open output file %s\n", OutfileName); out_fp = stdout; } if (out_fp != stdout) printf("\nOutput to file: %s\n", OutfileName); break; case 'F': fprintf(out_fp, "filename_trans rules:\n"); display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS, &policydb, out_fp); break; case 'l': link_module(&policydb, out_fp); break; case 'q': policydb_destroy(&policydb); exit(0); break; case 'm': menu(); break; default: printf("\nInvalid choice\n"); menu(); break; } } exit(EXIT_SUCCESS); } checkpolicy-2.2/test/dispol.c000066400000000000000000000322561223423440700163000ustar00rootroot00000000000000 /* Authors: Frank Mayer and Karl MacMillan * * Copyright (C) 2003 Tresys Technology, LLC * 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. */ /* * displaypol.c * * Test program to the contents of a binary policy in text * form. This program currently only displays the * avtab (including conditional avtab) rules. * * displaypol binary_pol_file */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static policydb_t policydb; void usage(char *progname) { printf("usage: %s binary_pol_file\n\n", progname); exit(1); } int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p, FILE * fp) { char *perm; fprintf(fp, "{"); perm = sepol_av_to_string(p, key->target_class, mask); if (perm) fprintf(fp, "%s ", perm); fprintf(fp, "}"); return 0; } int render_type(uint32_t type, policydb_t * p, FILE * fp) { fprintf(fp, "%s", p->p_type_val_to_name[type - 1]); return 0; } int render_key(avtab_key_t * key, policydb_t * p, FILE * fp) { char *stype, *ttype, *tclass; stype = p->p_type_val_to_name[key->source_type - 1]; ttype = p->p_type_val_to_name[key->target_type - 1]; tclass = p->p_class_val_to_name[key->target_class - 1]; if (stype && ttype) fprintf(fp, "%s %s : %s ", stype, ttype, tclass); else if (stype) fprintf(fp, "%s %u : %s ", stype, key->target_type, tclass); else if (ttype) fprintf(fp, "%u %s : %s ", key->source_type, ttype, tclass); else fprintf(fp, "%u %u : %s ", key->source_type, key->target_type, tclass); return 0; } /* 'what' values for this function */ #define RENDER_UNCONDITIONAL 0x0001 /* render all regardless of enabled state */ #define RENDER_ENABLED 0x0002 #define RENDER_DISABLED 0x0004 #define RENDER_CONDITIONAL (RENDER_ENABLED|RENDER_DISABLED) int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what, policydb_t * p, FILE * fp) { if (!(what & RENDER_UNCONDITIONAL)) { if (what != RENDER_CONDITIONAL && (((what & RENDER_ENABLED) && !(key-> specified & AVTAB_ENABLED)) || ((what & RENDER_DISABLED) && (key-> specified & AVTAB_ENABLED)))) { return 0; /* doesn't match selection criteria */ } } if (!(what & RENDER_UNCONDITIONAL)) { if (key->specified & AVTAB_ENABLED) fprintf(fp, "[enabled] "); else if (!(key->specified & AVTAB_ENABLED)) fprintf(fp, "[disabled] "); } if (key->specified & AVTAB_AV) { if (key->specified & AVTAB_ALLOWED) { fprintf(fp, "allow "); render_key(key, p, fp); render_access_mask(datum->data, key, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_AUDITALLOW) { fprintf(fp, "auditallow "); render_key(key, p, fp); render_access_mask(datum->data, key, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_AUDITDENY) { fprintf(fp, "dontaudit "); render_key(key, p, fp); /* We inverse the mask for dontaudit since the mask is internally stored * as a auditdeny mask */ render_access_mask(~datum->data, key, p, fp); fprintf(fp, ";\n"); } } else if (key->specified & AVTAB_TYPE) { if (key->specified & AVTAB_TRANSITION) { fprintf(fp, "type_transition "); render_key(key, p, fp); render_type(datum->data, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_MEMBER) { fprintf(fp, "type_member "); render_key(key, p, fp); render_type(datum->data, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_CHANGE) { fprintf(fp, "type_change "); render_key(key, p, fp); render_type(datum->data, p, fp); fprintf(fp, ";\n"); } } else { fprintf(fp, " ERROR: no valid rule type specified\n"); return -1; } return 0; } int display_avtab(avtab_t * a, uint32_t what, policydb_t * p, FILE * fp) { unsigned int i; avtab_ptr_t cur; avtab_t expa; if (avtab_init(&expa)) goto oom; if (expand_avtab(p, a, &expa)) { avtab_destroy(&expa); goto oom; } /* hmm...should have used avtab_map. */ for (i = 0; i < expa.nslot; i++) { for (cur = expa.htable[i]; cur; cur = cur->next) { render_av_rule(&cur->key, &cur->datum, what, p, fp); } } avtab_destroy(&expa); fprintf(fp, "\n"); return 0; oom: fprintf(stderr, "out of memory\n"); return 1; } int display_bools(policydb_t * p, FILE * fp) { unsigned int i; for (i = 0; i < p->p_bools.nprim; i++) { fprintf(fp, "%s : %d\n", p->p_bool_val_to_name[i], p->bool_val_to_struct[i]->state); } return 0; } void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp) { cond_expr_t *cur; for (cur = exp; cur != NULL; cur = cur->next) { switch (cur->expr_type) { case COND_BOOL: fprintf(fp, "%s ", p->p_bool_val_to_name[cur->bool - 1]); break; case COND_NOT: fprintf(fp, "! "); break; case COND_OR: fprintf(fp, "|| "); break; case COND_AND: fprintf(fp, "&& "); break; case COND_XOR: fprintf(fp, "^ "); break; case COND_EQ: fprintf(fp, "== "); break; case COND_NEQ: fprintf(fp, "!= "); break; default: fprintf(fp, "error!"); break; } } } int display_cond_expressions(policydb_t * p, FILE * fp) { cond_node_t *cur; cond_av_list_t *av_cur, *expl = NULL; avtab_t expa; for (cur = p->cond_list; cur != NULL; cur = cur->next) { fprintf(fp, "expression: "); display_expr(p, cur->expr, fp); fprintf(fp, "current state: %d\n", cur->cur_state); fprintf(fp, "True list:\n"); if (avtab_init(&expa)) goto oom; if (expand_cond_av_list(p, cur->true_list, &expl, &expa)) { avtab_destroy(&expa); goto oom; } for (av_cur = expl; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } cond_av_list_destroy(expl); avtab_destroy(&expa); fprintf(fp, "False list:\n"); if (avtab_init(&expa)) goto oom; if (expand_cond_av_list(p, cur->false_list, &expl, &expa)) { avtab_destroy(&expa); goto oom; } for (av_cur = expl; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } cond_av_list_destroy(expl); avtab_destroy(&expa); } return 0; oom: fprintf(stderr, "out of memory\n"); return 1; } int display_handle_unknown(policydb_t * p, FILE * out_fp) { if (p->handle_unknown == ALLOW_UNKNOWN) fprintf(out_fp, "Allow unknown classes and permisions\n"); else if (p->handle_unknown == DENY_UNKNOWN) fprintf(out_fp, "Deny unknown classes and permisions\n"); else if (p->handle_unknown == REJECT_UNKNOWN) fprintf(out_fp, "Reject unknown classes and permisions\n"); return 0; } int change_bool(char *name, int state, policydb_t * p, FILE * fp) { cond_bool_datum_t *bool; bool = hashtab_search(p->p_bools.table, name); if (bool == NULL) { fprintf(fp, "Could not find bool %s\n", name); return -1; } bool->state = state; evaluate_conds(p); return 0; } static void display_policycaps(policydb_t * p, FILE * fp) { ebitmap_node_t *node; const char *capname; char buf[64]; unsigned int i; fprintf(fp, "policy capabilities:\n"); ebitmap_for_each_bit(&p->policycaps, node, i) { if (ebitmap_node_get_bit(node, i)) { capname = sepol_polcap_getname(i); if (capname == NULL) { snprintf(buf, sizeof(buf), "unknown (%d)", i); capname = buf; } fprintf(fp, "\t%s\n", capname); } } } static void display_id(policydb_t *p, FILE *fp, uint32_t symbol_type, uint32_t symbol_value, char *prefix) { char *id = p->sym_val_to_name[symbol_type][symbol_value]; fprintf(fp, " %s%s", prefix, id); } static void display_permissive(policydb_t *p, FILE *fp) { ebitmap_node_t *node; unsigned int i; fprintf(fp, "permissive sids:\n"); ebitmap_for_each_bit(&p->permissive_map, node, i) { if (ebitmap_node_get_bit(node, i)) { fprintf(fp, "\t"); display_id(p, fp, SYM_TYPES, i - 1, ""); fprintf(fp, "\n"); } } } static void display_role_trans(policydb_t *p, FILE *fp) { role_trans_t *rt; fprintf(fp, "role_trans rules:\n"); for (rt = p->role_tr; rt; rt = rt->next) { display_id(p, fp, SYM_ROLES, rt->role - 1, ""); display_id(p, fp, SYM_TYPES, rt->type - 1, ""); display_id(p, fp, SYM_CLASSES, rt->tclass - 1, ":"); display_id(p, fp, SYM_ROLES, rt->new_role - 1, ""); fprintf(fp, "\n"); } } static void display_filename_trans(policydb_t *p, FILE *fp) { filename_trans_t *ft; fprintf(fp, "filename_trans rules:\n"); for (ft = p->filename_trans; ft; ft = ft->next) { display_id(p, fp, SYM_TYPES, ft->stype - 1, ""); display_id(p, fp, SYM_TYPES, ft->ttype - 1, ""); display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":"); display_id(p, fp, SYM_TYPES, ft->otype - 1, ""); fprintf(fp, " %s\n", ft->name); } } int menu() { printf("\nSelect a command:\n"); printf("1) display unconditional AVTAB\n"); printf("2) display conditional AVTAB (entirely)\n"); printf("3) display conditional AVTAG (only ENABLED rules)\n"); printf("4) display conditional AVTAB (only DISABLED rules)\n"); printf("5) display conditional bools\n"); printf("6) display conditional expressions\n"); printf("7) change a boolean value\n"); printf("8) display role transitions\n"); printf("\n"); printf("c) display policy capabilities\n"); printf("p) display the list of permissive types\n"); printf("u) display unknown handling setting\n"); printf("F) display filename_trans rules\n"); printf("\n"); printf("f) set output file\n"); printf("m) display menu\n"); printf("q) quit\n"); return 0; } int main(int argc, char **argv) { FILE *out_fp = stdout; char ans[81], OutfileName[121]; int fd, ret; struct stat sb; void *map; char *name; int state; struct policy_file pf; if (argc != 2) usage(argv[0]); fd = open(argv[1], O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open '%s': %s\n", argv[1], strerror(errno)); exit(1); } if (fstat(fd, &sb) < 0) { fprintf(stderr, "Can't stat '%s': %s\n", argv[1], strerror(errno)); exit(1); } map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { fprintf(stderr, "Can't map '%s': %s\n", argv[1], strerror(errno)); exit(1); } /* read the binary policy */ fprintf(out_fp, "Reading policy...\n"); policy_file_init(&pf); pf.type = PF_USE_MEMORY; pf.data = map; pf.len = sb.st_size; if (policydb_init(&policydb)) { fprintf(stderr, "%s: Out of memory!\n", argv[0]); exit(1); } ret = policydb_read(&policydb, &pf, 1); if (ret) { fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", argv[0]); exit(1); } fprintf(stdout, "binary policy file loaded\n\n"); close(fd); menu(); for (;;) { printf("\nCommand (\'m\' for menu): "); fgets(ans, sizeof(ans), stdin); switch (ans[0]) { case '1': display_avtab(&policydb.te_avtab, RENDER_UNCONDITIONAL, &policydb, out_fp); break; case '2': display_avtab(&policydb.te_cond_avtab, RENDER_CONDITIONAL, &policydb, out_fp); break; case '3': display_avtab(&policydb.te_cond_avtab, RENDER_ENABLED, &policydb, out_fp); break; case '4': display_avtab(&policydb.te_cond_avtab, RENDER_DISABLED, &policydb, out_fp); break; case '5': display_bools(&policydb, out_fp); break; case '6': display_cond_expressions(&policydb, out_fp); break; case '7': printf("name? "); fgets(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; name = malloc((strlen(ans) + 1) * sizeof(char)); if (name == NULL) { fprintf(stderr, "couldn't malloc string.\n"); break; } strcpy(name, ans); printf("state? "); fgets(ans, sizeof(ans), stdin); ans[strlen(ans) - 1] = 0; if (atoi(ans)) state = 1; else state = 0; change_bool(name, state, &policydb, out_fp); free(name); break; case '8': display_role_trans(&policydb, out_fp); break; case 'c': display_policycaps(&policydb, out_fp); break; case 'p': display_permissive(&policydb, out_fp); break; case 'u': case 'U': display_handle_unknown(&policydb, out_fp); break; case 'f': printf ("\nFilename for output ( for screen output): "); fgets(OutfileName, sizeof(OutfileName), stdin); OutfileName[strlen(OutfileName) - 1] = '\0'; /* fix_string (remove LF) */ if (strlen(OutfileName) == 0) out_fp = stdout; else if ((out_fp = fopen(OutfileName, "w")) == NULL) { fprintf(stderr, "Cannot open output file %s\n", OutfileName); out_fp = stdout; } if (out_fp != stdout) printf("\nOutput to file: %s\n", OutfileName); break; case 'F': display_filename_trans(&policydb, out_fp); break; case 'q': policydb_destroy(&policydb); exit(0); break; case 'm': menu(); break; default: printf("\nInvalid choice\n"); menu(); break; } } } /* FLASK */